C#BinaryFormatter – 使用另一个命名空间中的对象反序列化

最近,我们将部分代码移到了不同​​的项目库中。

不幸的是,似乎这些数据已经用BinaryFormatter序列化到数据库中(不要问我为什么,我不知道,我讨厌这个想法)。

现在我负责创建一个更新数据库的更新工具(当我们的软件根据版本检测到需要更新的数据库时,该工具会自动启动):

  1. 创建新列
  2. 反序列化二进制列
  3. 将反序列化的列写入新列
  4. 删除旧的二进制列

我的问题是,当我尝试反序列化时,它告诉我:

 Unable to find assembly 'MyOldAssemblyName, Version=2.0.0.0, Culture=neutral, PublicKeyToken=a5b9cb7043cc16da'. 

但是这个组件不再存在了。 我把这个类放在我的“更新程序”项目中没有问题,但我无法保持这个旧项目只包含这个文件。

有没有办法指定BinaryFormatter它必须反序列化它用指定类接收的Stream?

或者说组件已重命名,或???

要告诉它类型已在程序集之间移动(但它保留旧名称和命名空间),有时可以使用(在程序[assembly:TypeForwardedTo(typeof(TheType))][assembly:TypeForwardedTo(typeof(TheType))] 。 这里的“有时”是因为你需要使用typeof ,这意味着你需要从旧程序集到新程序集的引用,这并不总是可行 – 但通常是(特别是如果你从UI移动一个类型)层向下到POCO / DTO层,因为UI通常引用POCO / DTO)。

但是,如果您重命名了更改名称空间的类型,则需要您编写自定义“绑定器”( 请参阅此处 )。

应该注意的是, BinaryFormatter本质上是一个基于类型的序列化程序,在版本化或重构代码时总会遇到很多问题。 如果类型不是“一次写入,那么永远不会改变它”,那么我强烈建议使用更灵活的东西 – 一些是基于合同而不是基于类型的。 基本上,除了BinaryFormatter (或NetDataContractSerializer )之外的任何东西: XmlSerializerDataContractSerializer ,protobuf-net,Json.NET等中的任何一个都可以,并且不关心您重新定位或重命名类型。

事实上,我认为我发现自己是解决方案。

我们可以为二进制格式化程序提供SerializationBinder ,这将允许我们手动解析我们在流中找到的类。

这里有更多信息

我最近自己遇到了这个问题,并想发布我是如何设法解决这个问题的。 每个正常情况下序列化对象一切都是二进制格式化器反序列化的时候你可以使用Binder。 使用下面的活页夹,我简化了MSDN的解决方案,您需要做的就是将您使用的程序集的版本控制与类名一起交还。

  public object DeserializeObject() { BinaryFormatter binaryFormatter = new BinaryFormatter(); binaryFormatter.Binder = new VersionDeserializer(); using (MemoryStream memoryStream = new MemoryStream()) { try { memoryStream.Write(_data, _ptr, count); memoryStream.Seek(0, SeekOrigin.Begin); return binaryFormatter.Deserialize(memoryStream); } catch (Exception e) { return null; } } } sealed class VersionDeserializer: SerializationBinder { public override Type BindToType(string assemblyName, string typeName) { Type deserializeType = null; String thisAssembly = Assembly.GetExecutingAssembly().FullName; deserializeType = Type.GetType(String.Format("{0}, {1}", typeName, thisAssembly)); return deserializeType; } }