我正在尝试确定如何使用 protobuf-net(Marc Gravell 的实现)来解决这个用例。
- 我们有 A 类,它被认为是版本 1
- A 类的一个实例已序列化到磁盘
- 我们现在有了 B 类,它被认为是 A 类的第 2 版(A 类有很多问题,我们必须为下一个版本创建 B 类)。A 类仍然存在于代码中,但仅用于遗留目的。
- 我想将 version:1 数据(存储到磁盘)反序列化为 B 类实例,并使用逻辑例程将数据从先前的 A 类实例转换为 B 类的新实例。
- B 类的实例将在运行期间被序列化到磁盘。
- 应用程序应该期望反序列化 A 类和 B 类的实例。
我想到了数据契约代理和 DataContractSerializer 的概念。目标是将 version:1 数据转换为新的 B 类结构。
一个例子:
[DataContract]
public class A {
public A(){}
[DataMember]
public bool IsActive {get;set;]
[DataMember]
public int VersionNumber {
get { return 1; }
set { }
}
[DataMember]
public int TimeInSeconds {get;set;}
[DataMember]
public string Name {get;set;}
[DataMember]
public CustomObject CustomObj {get;set;} //Also a DataContract
[DataMember]
public List<ComplexThing> ComplexThings {get;set;} //Also a DataContract
...
}
[DataContract]
public class B {
public B(A a) {
this.Enabled = a.IsActive; //Property now has a different name
this.TimeInMilliseconds = a.TimeInSeconds * 1000; //Property requires math for correctness
this.Name = a.Name;
this.CustomObject2 = new CustomObject2(a.CustomObj); //Reference objects change, too
this.ComplexThings = new List<ComplexThings>();
this.ComplexThings.AddRange(a.ComplexThings);
...
}
public B(){}
[DataMember]
public bool Enabled {get;set;]
[DataMember]
public int Version {
get { return 2; }
set { }
}
[DataMember]
public double TimeInMilliseconds {get;set;}
[DataMember]
public string Name {get;set;}
[DataMember]
public CustomObject2 CustomObject {get;set;} //Also a DataContract
[DataMember]
public List<ComplexThing> ComplexThings {get;set;} //Also a DataContract
...
}
A 类是我们对象的第一次迭代,并且正在积极使用中。数据以 v1 格式存在,使用 A 类进行序列化。
在意识到我们方法的错误之后,我们创建了一个新的结构,称为 B 类。A 和 B 之间有很多变化,我们觉得创建 B 更好,而不是适应原来的 A 类。
但是我们的应用程序已经存在,并且 A 类正在用于序列化数据。我们已经准备好将我们的更改推广到世界各地,但我们必须首先反序列化在版本 1 下创建的数据(使用 A 类)并将其实例化为 B 类。数据足够重要,我们不能只假设类中的默认值B 表示缺少数据,而是我们必须将数据从 A 类实例转换到 B 类。一旦我们有了 B 类实例,应用程序将以 B 类格式(版本 2)再次序列化该数据。
我们假设我们将来会对 B 类进行修改,并且我们希望能够迭代到版本 3,也许在一个新的“C”类中。我们有两个目标:处理已经存在的数据,并为将来的迁移准备我们的对象。
现有的“转换”属性(OnSerializing/OnSerialized、OnDeserializing/OnDeserialized 等)不提供对先前数据的访问。
在这种情况下使用 protobuf-net 时的预期做法是什么?