版本容错序列化 - 如何查找原始的AssemblyName

Dav*_*nde 3 c# serialization

在.NET 2.0(以及我认为更高版本)中,版本容忍序列化将成功地从对象所在的程序集的旧版本反序列化序列化对象.

当我使用十六进制查看器打开这样一个二进制格式化的序列化流时(一个简单的拖放到VS中)我可以看到这个流中包含的汇编信息.

在反序列化期间,是否有检索此信息的方法?例如,这可用于在读取旧内容时将修正应用于已知问题.

更新:看起来它无法完成(除了更改类本身,如Paul Betts的回答,也没有测试过)所以有没有其他方法来读取这个值?是否发布了二进制格式?

Con*_*dev 5

我在编写CodeProject文章时亲自发现了这些序列化问题(滚动到'从磁盘加载目录',大约一半).

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

无论如何,我的第一点是在反序列化期间抛出的异常包括强名称

找不到程序集h4octhiw,Version = 0.0.0.0,Culture = neutral,PublicKeyToken = null

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

第二点涉及我实施的解决方案(使用此信息).我写了一个自定义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));
        }
    } 
}
Run Code Online (Sandbox Code Playgroud)

基本上BindToType,反序列化过程有机会将已知类型替换为最初用于序列化该对象的类型.我只使用typeName,但assemblyName可能包含您所追求的信息,并且自定义SerializationBinder可能是您应该调查以"使用"它的方法.

仅供参考,上面的代码是这样的"连线":

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); 
Run Code Online (Sandbox Code Playgroud)