Самый простой метод, который я имел разумные долгосрочные результаты заключаются в том, чтобы обеспечить (в настоящее время и навсегда) ваш собственный контракт, что каждый класс имеет как минимум свойство Версии, которое в сочетании с типом дает вам уникальный идентификатор, чтобы позже рассказать вам, как десериализовать объект.Вы также можете создавать объекты из разных классов в зависимости от версии # ваших сохраненных данных, поэтому не выполняйте управление версиями внутри класса, сделайте это, например, с помощью объекта Persister, который работает на любом объекте, реализующем ваш интерфейс с состоянием:
Сначала используйте прикладную шириной Enum для основных типов вашего приложения объекта (не каждый класс):
Public Enum MyObjectTypesEnum
Unspecified = 0
Fish = 1
Cow = 2
End Enum
Тогда ваш интерфейс:
Public Interface IStateful
ReadOnly Property Version As Integer
ReadOnly Property ObjectType As MyObjectTypesEnum
Sub SetState(Info As SerializationInfo)
Sub GetState(Info As SerializationInfo)
End Interface
Шаг 1 в сохраняющихся свои объекты для хранения версии и введите:
Public Sub SaveTheBasics(Info As SerializationInfo, TheObject as IStateful)
Info.SetInt64(TheObject.Version,"Version")
Info.SetInt64(TheObject.ObjectType,"ObjectType")
Это хранит всю необходимую информацию, чтобы справиться с различными версиями в будущем:
Dim TheObject as IStateful
Select Case Info.GetInt64("ObjectType")
Case MyObjectTypesEnum.Fish
Select Case Info.GetInt64("Version")
Case Is < 2
TheObject = New OldestFishClass
Case Is < 5
TheObject = New OldFishClass
Case Else
TheObject = New NewFishClass
End Select
Case MyObjectTypesEnum.Cow
...
End Select
TheObject.SetState(Info)
etc etc.
Если политика вашего приложения является настоять данные хранятся в самой последней версии, то при загрузке и обновление данных предыдущей версии, вы можете создать экземпляр старого класса, и использовать это в перегруженном методе загрузки вашего новейших класса обновление:
Select Case Info.GetInt64("Version")
...
Case Is < 5
Dim TempOldObject As New OldFishClass
TempOldObject.SetState(Info)
TheObject = New NewFishClass
TheObject.SetState(TempOldObject)
Case Else
TheObject = New NewFishClass
TheObject.SetState(Info)
End Select
...
... и убедитесь, что у наш новый класс знает, как загрузить его предыдущую версию, как показано ниже.
Вы можете использовать базовый класс, который реализует интерфейс для всех сохраняющих состояние объектов, а также имеет все свойства, все ваши объекты, возможно, потребуется:
Public MustInherit Class MyBaseClass
Implements IStateful
Public MustOverride Readonly Property VersionNumber As Integer Implements IStateful.Version
Public MustOverride Readonly Property ObjectType As MyObjectTypesEnum Implements IStateful.ObjectType
Public UniqueID As GUID
...
Public Class NewFishClass
Inherits MyBaseClass
Public Overrides ReadOnly Property VersionNumber As Integer
Get
Return 5
End Get
End Property
Public Overrides ReadOnly Property ObjectType As MyObjectTypesEnum
Get
Return MyObjectTypesEnum.Fish
End Get
End Property
'Overloaded state-setting methods (could be Constructors instead):
Public Sub SetState(Info As SerializationInfo)
Me.ScaleCount = Info.GetInt64("ScaleCount")
End Sub
Public Sub SetState(OldFish As OldFishClass)
'Upgrade from V2:
Me.ScaleCount = OldFish.LeftScales + OldFish.RightScales
End Sub
Public Sub SetState(OldestFish As OldestFishClass)
'Upgrade from V1
Me.ScaleCount = OldFish.Length * OldFish.ScalesPerUnitLength)
End Sub
etc etc.
Главный принцип здесь в том, что договор содержится в интерфейсах , и, насколько это возможно, базовый класс выполняет необходимую работу по выполнению этого контракта. Затем для создания 30 классов вы наследуете каждого из базового объекта. Если вы построили его правильно, вы будете вынуждены предоставить информацию, необходимую для правильного управления версиями и устойчивости (вы также создаете слои абстракции, которые, конечно же, в какой-то момент вы будете благодарны).
В больших проектах я расширяю такое мышление, чтобы сохраняемые свойства каждого объекта содержались в объекте «State», который происходит из базового класса StateBase, который сам реализует интерфейс IState. Затем Persistance действует на любой объект StateBase. Я также использую класс CollectionBase (который также наследует от моего базового класса), который обрабатывает экземпляр и заполнение содержащихся объектов. Часто вашим объектам необходимо хранить ссылки друг на друга через сеансы, поэтому для восстановления этих ссылок требуется уникальный идентификатор (GUID), который входит в базовый объект.
Десуриализация в измененный класс является проблемой только с BinaryFormatter. XMLSerialization и ProtoBuf-NET не имеют этой проблемы. – Plutonix