反序列化对象时重写程序集/类型
序列化对象时,格式化器输出类型及其定义的程序集全名。反序列化对象时,格式化器根据这个信息确定要为对象构造并初始化什么类型。但是有时候有必要将对象反序列成和序列化时不同的类型。
1. 一个类型的实现从一个程序集移到了另一个程序集。
2. 服务器对象序列化传输给客户端,客户端反序列不同类型的对象。
3. 开发人员创建了类型的新版本,想把已序列化的对象反序列化到类型的新版本。
根据之前的文章是可以做到的,但是比较繁琐。
本文会提供另一种机制,可以非常简单地将一个对象流反序列化成不同类型的对象。
利用SerializationBinder类,可以方便满足我们的需求。
1. 首先有一个名为Ver1类。
2. 然后还有一个名为Ver2类。
3. 自定义一个Ver1ToVer2SerializationBinder类,它继承SerializationBinder类。
4. 重写SerializationBinder类的BindToType方法,把Ver1的对象流反序列化成Ver2对象。
5. 构造自定义的SerializationBinder类的实例并设置格式化器的Binder属性。
6. 格式化器在调用Deserialize方法的时候,它会检查Binder属性,格式化器会调用里面的BindToType方法,向它传递程序集名称以及格式化器想要反序列化的类型。然后BindToType根据这个类型判断出来实际应该构建什么类型,并返回这个类型。
代码简单实现:
[Serializable]
class Ver1
{
public int MyProperty { get; set; }
}
[Serializable]
class Ver2
{
public int MyProperty { get; set; }
}
class Ver1ToVer2SerializationBinder: SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
AssemblyName assemblyVer1 = Assembly.GetExecutingAssembly().GetName();
assemblyVer1.Version = new Version(1, 0, 0, 0);
if (assemblyName == assemblyVer1.ToString() && typeName == "SerializeDemo.SerializationBinderDemo.Ver1")
{
return typeof(Ver2);
}
return Type.GetType(string.Format("{0}, {1}", typeName, assemblyName));
}
}
using (MemoryStream stream = new MemoryStream())
{
IFormatter formatter = new BinaryFormatter();
formatter.Binder = new Ver1ToVer2SerializationBinder();
Ver1 ver1 = new Ver1() { MyProperty = 3 };
formatter.Serialize(stream, ver1);
stream.Position = 0;
var ver2 = (Ver2)formatter.Deserialize(stream);
}
SerializationBinder类里面还有一个BindToName方法,
public virtual void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = null;
typeName = null;
}
它是一个虚方法,可以重写。
通过这个方法可以在序列化对象时更改程序集和类型的信息。
格式化器调用这个方法,获取应该序列化成为什么类型,我们可以通过重写这个方法,给out string assemblyName和out string typeName返回真正想要序列化到的类型。默认两个参数都是返回null,就不执行任何程序集和类型的更改。
本文回顾:
反序列化对象时重写程序集/类型?
重写SerializationBinder类的BindToType方法。
序列化对象时重写程序集/类型?
重写SerializationBinder类的BindToName方法。
-纸上得来终觉浅,绝知此事要躬行-