如何用新的ISerializable类替换旧类
本文关键字:替换 ISerializable 何用新 | 更新日期: 2023-09-27 18:20:35
我们有一个遗留类A
,它是[Serializable]
,但不是ISerializable
。由于各种原因,必须对此类进行修补才能实现ISerializable。
问题是,我们仍然需要能够加载旧的保存文件,该文件使用.NET的默认实现来序列化类A
。换句话说,当加载旧的保存文件时,类A
必须像旧版本一样反序列化,然后转换为类A
的新版本,这样在再次保存时,将使用我们的ISerializable
的新实现。
在不破坏向后兼容性的情况下,修补类A
最合适的方法是什么?
解决方案1
首先,更改项目的程序集版本。
// AssemblyInfo.cs:
[assembly: AssemblyVersion("2.0.0.0")]
为保存游戏数据创建一个新类型。
// The legacy savegame data. Keep it as it is.
[Serializable]
public class Savegame
{
// ... the legacy fields
}
// The new savegame data. This implements ISerializable
[Serializable]
public class SavegameNew : Savegame, ISerializable
{
// this constructor will execute on deserialization. You will deserialize
// both the legacy and new types here.
private SavegameNew(SerializationInfo info, StreamingContext context)
{
foreach (SerializationEntry entry in info)
{
// you can iterate the serialized elements like this
// if this is a new format you will get the new elements, too
}
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
// custom serialization of the new type
}
}
现在,您需要一个将旧格式映射到新格式的绑定器类:
internal class SavegameBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
// Of course, use the assembly version of the old version here.
// You don't even need to change the assembly version, though than can lead to ambiguity
AssemblyName asmName = new AssemblyName(assemblyName);
if (asmName.Version == new Version(1, 0, 0, 0) && typeName == typeof(Savegame).FullName)
return typeof(SavegameNew);
// otherwise we do not change the mapping
return null;
}
}
你可以这样使用它:
// the saveStream can contain either the old other the new format
BinaryFormatter bf = new BinaryFormatter() { Binder = new SavegameBinder() };
SavegameNew data = (SavegameNew)bf.Deserialize(saveStream);
解决方案2
使用此解决方案,您不需要将Savegame
映射到SavegameNew
。如果不更改程序集版本,则甚至不需要binder类。
如果更改了程序集版本,则SavegameBinder
应返回新程序集的Savegame
类型。遗留的Savegame
应该实现IObjectReference
接口,因此一旦它被反序列化,它就可以返回一个SavegameNew
实例。
// The legacy savegame data
[Serializable]
public class Savegame: IObjectReference
{
// ... the legacy fields
public object GetRealObject(StreamingContext context)
{
return new SavegameNew(...);
}
}