c# - 如何用新的 ISerialized 类替换旧类

标签 c# .net serialization c++-cli binaryformatter

我们有一个遗留类A,它是[Serializable],但不是ISerialized。 由于各种原因,必须修补此类以实现 ISerialized。

问题是我们仍然需要能够加载旧的保存文件,该文件使用 .NET 的默认实现来序列化类 A。 换句话说,当加载旧的保存文件时,类A必须像旧版本一样被反序列化,然后转换为新版本的类A,这样当再次保存时,我们使用了 ISerialized 的新实现。

在不破坏向后兼容性的情况下修补类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
    }
}

现在您需要一个将旧格式映射到新格式的 Binder 类:

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 接口(interface),因此一旦反序列化,它就可以返回 SavegameNew 实例。

// The legacy savegame data
[Serializable]
public class Savegame: IObjectReference
{
    // ... the legacy fields

    public object GetRealObject(StreamingContext context)
    {
        return new SavegameNew(...);
    }
}

关于c# - 如何用新的 ISerialized 类替换旧类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33544378/

相关文章:

c# - WCF IDispatchMessageInspector

.net - 是一对一还是组件?休眠映射

c# - 如何将任何对象类型转换为实际类型

c# - 将对象序列化为 XML,仅使用引用 ID

python - 将 Appengine 数据存储区中的 ReferenceProperty 序列化为 JSON

c# - 在最小起订量中使用 Match.Create

c# - WPF TreeView 双击后恢复焦点

.net - 安装 Windows 服务并进行恢复操作以重新启动

perl - 如何通过 Telnet 将 Tcl 数据结构传递给 Perl?

c# - Azure 网站或 Azure 云服务上的 MVC4 API [错误] : 'System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption'