【问题标题】:C# Deserialize a class which has moved or been renamedC#反序列化已移动或重命名的类
【发布时间】:2009-09-23 10:02:17
【问题描述】:
如果我在名为“AssemblyA”的程序集中有一个名为“MyClass”的类,并使用 .NET 的 BinaryFormatter 将其序列化为文件。然后将“MyClass”的代码移动到名为“AssemblyB”的程序集中并尝试反序列化文件我得到以下“System.TypeLoadException”异常:
无法从程序集“AssemblyA,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”加载类型“AssemblyA.MyClass”。
我有什么方法可以表明该课程已移至 AssemblyB?通过某种属性?或者是否可以修改序列化文件作为预处理步骤以将所有引用从 AssemblyA.MyClass 更改为 AssemblyB.MyClass?最后,如果这两个选项都不可行,是否可以绕过尝试反序列化此类并继续反序列化其余数据?
【问题讨论】:
标签:
c#
serialization
binary
【解决方案1】:
如果你已经移动了它,那么添加一个对它现在所在的dll的引用,并使用TypeForwardedToAttribute:
[assembly:TypeForwardedTo(typeof(TheType))]
这对于一些在新程序集中寻找类型的请求(包括BinaryFormatter IIRC)来说已经足够了。但是,IIRC 它只适用于最外层的类型(不是嵌套类型,可能不是泛型),你不能重命名它/更改命名空间/等等。
重命名比较麻烦...BinaryFormatter 对这些事情是出了名的脆弱。 IMO,它只适用于序列化两个紧密耦合系统之间的瞬态数据(例如,在同一进程中的两个AppDomains 之间交换;用于存储时,或者可能会失去同步的系统之间,它可以是一个噩梦。
可能为时已晚,但我建议使用基于合约的序列化程序(而不是基于类型的序列化程序); XmlSerializer、DataContractSerializer 中的任何一个(只要你使用[DataContract]/[DataMember] 属性)等等。如果你想要快速二进制,protobuf-net 会做得很好(并且可以挂钩到 @987654331 @如果你需要)。
另一个可能值得研究的概念是序列化代理,但这相对较难。但是 IIRC 这使您可以控制所创建的类型 - 但您需要为它做很多工作。