2014-10-21 2 views
1

Я пытаюсь десериализовать некоторые объекты, которые были сериализованы со старой версией моего приложения, чтобы обновить их до нового формата, который я использую в новой версии приложения.Deserializing производные классы с пользовательским SerializationBinder

Для этого я использую пользовательский 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 объект. Оба объекта абсолютно одинаковы, но программа не десериализует свойства a и b.

Вот выход я получаю: а = 0 Ь = 0 с = 3 d = 4

Я полагаю, что проблема связана с авто-свойств. Если я удалю {get;set;} и превращу их в поля, то он будет работать. Но объекты v1 в моем приложении являются свойствами, поэтому я должен работать с этим.

Итак, вопрос: как я могу заставить эту десериализацию работать правильно?

ответ

1

Вы должны предоставить конструктор десериализации и реализовать ISerializable для новых типов версий. Старые члены версии могут быть доступны из SerializationInfo с помощью вспомогательного класса SerializationHelper:

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); 
    } 
} 
+0

Это, кажется, работает, но есть ли способ сделать это без изменения '' v1base' и классов v1derived'? Мне нужно сделать это в более крупном приложении, где я хочу перенести некоторые старые объекты, и я не могу изменить их определение. – Ove

+0

Я сделал еще несколько копаний, и похоже, что вы можете получить значения без изменения 'v1base' и' v1derived'. Вам нужно изменить вызов внутри конструктора сериализации v2base и v2derived на что-то вроде этого, и он будет работать: 'a = info.GetInt32 (" v1base + k__BackingField ");' (то же самое для b, c и d) – Ove

+0

Да, я Я сделал то же самое сейчас :) Интересно, я никогда не делал этого до –

Смежные вопросы