2009-06-04 54 views
3

在.NET 2.0(及其以上版本,我推测)中,版本容忍序列化将成功地从该对象所在的程序集的较早版本反序列化一个序列化对象。版本容忍序列化 - 如何查找原始版本的组件名称

当我使用十六进制查看器打开这样一个二进制格式的串行化流时(VS中的简单拖放操作将会执行),我可以看到这个流中包含汇编信息。

在反序列化过程中,有没有办法检索这些信息?例如,这可用于在旧版内容中阅读时将修正应用于已知问题。

更新: 它看起来不能做(除了改变类本身,就像在Paul Betts的回答中,没有测试那样),所以还有其他方法来读取这个值吗?二进制格式是否发布?

+0

相关(但不相同):http://stackoverflow.com/questions/929985#930135 - 总之,我不不认为BinaryFormatter“版本”(好)在版本之间...有更好的选择。 – 2009-06-04 14:47:50

+0

或http://stackoverflow.com/questions/881766#881898(再次 - 这只是相关的 - 不是一个复制等) – 2009-06-04 14:50:01

回答

5

我在编写this CodeProject article时发现了这些序列化问题(滚动到“从磁盘加载目录”,大约过了一半)。

基本上我是用ASP.NET应用程序序列化一些东西 - 并且在重新启动IIS应用程序后(由于ASP.NET所做的整个动态编译/临时程序集缓存等),序列化数据无法读取!哎哟!

不管怎样,我的第一点是反序列化期间抛出的异常包括强名称

找不到装配h4octhiw,版本= 0.0.0.0,文化=中立,公钥=空

很显然你是正确的,你想要的信息是在那里“某处”。理论上(是的,这是一个可怕的想法),你可以捕获序列化异常并解析旧版本细节的错误(当然,'当前'反序列化不会抛出)......但也可能有更好的方法..

第二点涉及我实施的解决方案(使用this info)。我写了一个自定义System.Runtime.Serialization.SerializationBinder:下面显示的代码是一个例子。

public class CatalogBinder: System.Runtime.Serialization.SerializationBinder 
{ 
    public override Type BindToType (string assemblyName, string typeName) 
    { 
     // get the 'fully qualified (ie inc namespace) type name' into an array 
     string[] typeInfo = typeName.Split('.'); 
     // because the last item is the class name, which we're going to 
     // 'look for' in *this* namespace/assembly 
     string className=typeInfo[typeInfo.Length -1]; 
     if (className.Equals("Catalog")) 
     { 
      return typeof (Catalog); 
     } 
     else if (className.Equals("Word")) 
     { 
      return typeof (Word); 
     } 
     if (className.Equals("File")) 
     { 
      return typeof (File); 
     } 
     else 
     { // pass back exactly what was passed in! 
      return Type.GetType(string.Format("{0}, {1}", typeName, 
           assemblyName)); 
     } 
    } 
} 

基本上BindToType报错由反序列化过程为“替代”的最初用于序列化该对象的一个​​已知类型的机会。我只使用typeName,但assemblyName可能包含您之后的信息,并且自定义SerializationBinder可能是您应该调查以“使用”它的方法。

FYI,代码上面 '有线了' 是这样的:

System.Runtime.Serialization.IFormatter formatter = 
    new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 
formatter.Binder = new CatalogBinder(); // THIS IS THE IMPORTANT BIT 
object deserializedObject = formatter.Deserialize(stream); 
1

一个字段添加到您的所有序列化类调用程序集信息时设置到Assembly.GetExecutingAssembly()。全​​名

0

使用鲁兹罗德斯(现红门)Reflector

System.Runtime.Serialization.Formatters.Binary.__BinaryParser类在内部使用由BinaryFormatterDeserialize方法做实际的解析。

在反射器中四处移动可能会给您提示如何预读二进制文件头并确定版本信息。