使用自定义SerializationBinder反序列化派生类

时间:2014-10-21 09:17:09

标签: c# .net serialization binary-serialization

我正在尝试反序列化使用旧版本的应用程序序列化的某些对象,以便将它们升级到我在新版本的应用程序中使用的新格式。

为了做到这一点,我使用自定义SerializationBinder将旧对象映射到新对象。

我能够以这种方式迁移我的大多数对象,但是当我的一个对象派生自基类时,我遇到了问题。问题是基类中的属性不会被反序列化(只有派生类中的属性才会被反序列化)。

我能够将问题缩小为一个简短的自包含程序,我将在此处粘贴:

namespace SerializationTest
{
class Program
{
    static void Main(string[] args)
    {
        v1derived first = new v1derived() { a = 1, b = 2, c = 3, d = 4 };
        v2derived second = null;

        BinaryFormatter bf = new BinaryFormatter();
        bf.Binder = new MyBinder();

        MemoryStream ms = new MemoryStream();
        bf.Serialize(ms, first);
        ms.Seek(0, SeekOrigin.Begin);
        second = (v2derived)bf.Deserialize(ms);
        Console.WriteLine("a={0} b={1} c={2} d={3}", second.a, second.b, second.c, second.d);
    }
}

class MyBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        if (typeName == "SerializationTest.v1base")
        {
            return typeof(v2base);
        }
        if (typeName == "SerializationTest.v1derived")
        {
            return typeof(v2derived);
        }
        return null;
    }
}

[Serializable]
class v1base
{
    public int a { get; set; }
    public int b { get; set; }
}

[Serializable]
class v1derived : v1base
{
    public int c { get; set; }
    public int d { get; set; }
}

[Serializable]
class v2base
{
    public int a { get; set; }
    public int b { get; set; }
}

[Serializable]
class v2derived : v2base
{
    public int c { get; set; }
    public int d { get; set; }
}
}

在这个程序中,我正在序列化一个v1derived对象,并尝试将其反序列化为v2derived对象。两个对象完全相同,但程序不会反序列化ab属性。

以下是我得到的输出:     a = 0 b = 0 c = 3 d = 4

我认为问题与自动属性有关。如果我删除{get;set;}并将其转换为字段,那么它将起作用。但我的应用程序中的v1对象是属性,所以我必须使用它。

所以问题是:如何让这个反序列化正常工作?

1 个答案:

答案 0 :(得分:1)

您应该提供反序列化构造函数并为新版本类型实现ISerializable。 可以使用帮助程序类SerializationHelper:

从SerializationInfo访问旧版本成员
static class SerializationHelper
{
    public static string GetAutoPropertyName(string baseTypeName, string name)
    {
        return baseTypeName + "+<" + name + ">k__BackingField";
    }

    public static string GetAutoPropertyName(string name)
    {
        return "<" + name + ">k__BackingField";
    }
}

[Serializable]
class v2base : ISerializable
{
    protected v2base(
        SerializationInfo info,
        StreamingContext context)
    {
        a = info.GetInt32(SerializationHelper.GetAutoPropertyName("v1base", "a"));
        b = info.GetInt32(SerializationHelper.GetAutoPropertyName("v1base", "b"));
    }

    public int a { get; set; }
    public int b { get; set; }

    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue(SerializationHelper.GetAutoPropertyName("v1base", "a"), a);
        info.AddValue(SerializationHelper.GetAutoPropertyName("v1base", "b"), b);
    }
}

[Serializable]
class v2derived : v2base
{
    protected v2derived(
        SerializationInfo info,
        StreamingContext context) : base(info, context)
    {
        c = info.GetInt32(SerializationHelper.GetAutoPropertyName("c"));
        d = info.GetInt32(SerializationHelper.GetAutoPropertyName("d"));
    }

    public int c { get; set; }
    public int d { get; set; }

    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
        info.AddValue(SerializationHelper.GetAutoPropertyName("c"), c);
        info.AddValue(SerializationHelper.GetAutoPropertyName("c"), d);
    }
}