在我的项目中,我有一个以二进制格式序列化到磁盘的类。
由于一些新的要求,我需要创建一个派生自原始类的新类。
例如
[Serializable]
public class Sample
{
String someString;
int someInt;
public Sample()
{
}
public Sample(String _someString, int _someInt)
{
this.someInt = _someInt;
this.someString = _someString;
}
public String SomeString
{
get { return someString; }
}
public int SomeInt
{
get { return someInt; }
}
}
[Serializable]
public class DerivedSample : Sample
{
String someMoreString;
int someMoreInt;
public DerivedSample ()
: base()
{
}
public DerivedSample (String _someString, int _someInt, String _someMoreString, int _someMoreInt)
:
base(_someString, _someInt)
{
this.someMoreString = _someMoreString;
this.someMoreInt = _someMoreInt;
}
public String SomeMoreString
{
get { return someMoreString; }
}
public int SomeMoreInt
{
get { return someMoreInt; }
}
}
当我尝试序列化一个只包含Sample对象的旧文件时,它在当前程序集中工作正常。这意味着向后兼容性存在。但是当我尝试使用以前版本的程序集应用程序崩溃时反序列化包含DerivedSample对象的文件时。这意味着需要关注前向兼容性......
可以说从新版本的文件中只读取对象的基类部分吗?
答案 0 :(得分:2)
从问题看来,失败的是尝试将序列化的DerivedSample读入具有旧版本程序集的应用程序中 - 因此没有DerivedSample类,只有Sample类。
我不认为这是有用的,因为序列化的类(DerivedSample)在反序列化应用程序中根本不存在任何形式。
当类本身被版本化而不是使用继承时,序列化似乎最有效。因此,您可以修改Sample以添加新属性,而不是从中派生。新字段应标记为可选(提供向后兼容性),并且在反序列化为旧版本时忽略无关字段(提供向前兼容性):http://msdn.microsoft.com/en-us/library/ms229752(VS.80).aspx
这是你的选择吗?
答案 1 :(得分:1)
此新是否正常工作或现有有效吗? BinaryFormatter
对于这样的事情非常敏感,但是如果你想要二进制输出,你可能想要考虑像protobuf-net这样的东西,它使用更可预测的基于契约的输出;这意味着如果您更改特定类型,您可以将数据恢复到您的应用 。
如果二进制文件不重要,您也可以考虑使用xml; XmlSerializer
,DataContractSerializer
等IMO,BinaryFormatter
不应用于持久数据以用于除最短时间之外的任何其他内容。
你强调前向/后向兼容性很重要;在这种情况下,我强烈敦促你BinaryFormatter
可以用这个硬。
答案 2 :(得分:0)
可以说只读 来自new的对象的基类部分 该文件的版本?
在这种情况下,最好将对象反序列化为Sample
,然后在DerivedSample
中提供复制必要属性的构造函数。这样,您可以保持与先前对象的向后兼容性,但仍然可以使用较新的类。
另外,WCF序列化处理了很多对象版本问题。如果您的项目需要与对象版本控制的向后/向前兼容性,您可以考虑切换到使用DataContracts进行序列化。
-Doug
答案 3 :(得分:0)
您需要使用所谓的序列化代理。您可以将其注入二进制序列化程序,然后在运行时,代理可以替换为您自己的类型序列化/反序列化的内容。我曾经在程序集之间移动类型并且代码不再能够反序列化旧文件时使用它。更多关于这里的代理人: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.surrogateselector(v=VS.100).aspx