使用iserializable接口时在c#中进行版本控制序列化

时间:2014-04-14 07:38:05

标签: c# serialization

我有一个基类FDObjectBase,它继承自ContentControl,ISerializable,INotifyPropertyChanged。现在使用下面的代码逻辑

对该类进行反序列化
public FDObjectBase(SerializationInfo info, StreamingContext context) : this()
{
   Left = (double)info.GetValue("Left", typeof(double));
    Top = (double)info.GetValue("Top", typeof(double));
    Height = (double)info.GetValue("Height", typeof(double));
    Width = (double)info.GetValue("Width", typeof(double));
    DesignObjectID = (int)info.GetValue("DesignObjectID", typeof(int));
    ShapeType = (int)info.GetValue("ShapeType", typeof(int));
    Angle = (double)info.GetValue("Angle", typeof(double));
    try
    {
        ObjectType = (ObjectType)info.GetValue("ObjectType", typeof(ObjectType));
        //this.ToolTip = ObjectType.ToString();
    }
    catch { }

    OnDeserialized(new EventArgs());
    //DataObject = (DesignData)info.GetValue("DataObject", typeof(DesignData));
    //this.ToolTip = DataObject.Name + " (" + DataObject.ObjectType.ToString().ToLower() + ")";    

}

这在应用程序中工作正常但问题是我希望反序列化过程是向后兼容的,因为根据要求,对此类的更改不得破坏存储在数据库中的反序列化数据。 我找到的解决方案是将[OptionalField]属性添加到添加到此类的所有新字段中,但这对我来说没有用。当我在这个类中添加一个新字段时,我仍然得到相同的异常(在添加新字段后,反序列化不会发生,并抛出以下异常)

System.Reflection.TargetInvocationException was caught
  Message=Exception has been thrown by the target of an invocation.
  Source=mscorlib
  StackTrace:
       at System.RuntimeMethodHandle._SerializationInvoke(IRuntimeMethodInfo method, Object target, SignatureStruct& declaringTypeSig, SerializationInfo info, StreamingContext context)
       at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context)
       at System.Runtime.Serialization.ObjectManager.FixupSpecialObject(ObjectHolder holder)
       at System.Runtime.Serialization.ObjectManager.DoFixups()
       at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
       at .SeatManagement.Client.Helpers.Generics.Deserialize[T](String data) in Generics.cs:line 117
  InnerException: System.Runtime.Serialization.SerializationException
       Message=Member 'Test' was not found.
       Source=mscorlib

因此,当我们使用iserializable接口时,我正在寻找在版本化序列化c#方向上的任何建议,以便在我们向类添加新字段时它不会中断。在此先感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

最后我找到了解决方案..但是它没有使用System.Runtime.Serialization提供的开箱即用功能。 我在我的基类

上添加了一个属性版本
private static int VERSION_NUMBER = 1;

与其他设计属性一起序列化,如下所示。

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
    info.AddValue("Version", VERSION_NUMBER);
    //First Version properties
    info.AddValue("Left", Left);
    info.AddValue("Top", Top);
    info.AddValue("Height", Height);
    info.AddValue("Width", Width);
    info.AddValue("DesignObjectID", DesignObjectID);
    info.AddValue("ShapeType", ShapeType);
    info.AddValue("ObjectType", ObjectType.GetIntValue());
    info.AddValue("Angle", Angle);
    //Second Version Properties
}

现在当我反序列化字符串时,我检查存储在反序列化字符串中的版本

public FDObjectBase(SerializationInfo info, StreamingContext context) : this()
{
    int version = Generics.GetSerializedValue<int>(info, "Version");

    if (version >= 1)
    {
        Left = (double)info.GetValue("Left", typeof(double));
        Top = (double)info.GetValue("Top", typeof(double));
        Height = (double)info.GetValue("Height", typeof(double));
        Width = (double)info.GetValue("Width", typeof(double));
        DesignObjectID = (int)info.GetValue("DesignObjectID", typeof(int));
        ShapeType = (int)info.GetValue("ShapeType", typeof(int));
        Angle = (double)info.GetValue("Angle", typeof(double));
        ObjectType = ((int)info.GetValue("ObjectType", typeof(int))).GetEnumValue<ObjectType>();
    }
    if (version >= 2)
    {
        //Add newly added properties for this version
    }
    else { 
        //Add default values for new properties for this version
    }

    OnDeserialized(new EventArgs());

} 

所以现在当我添加一个之前未反序列化的新属性时,我只需增加版本并在第二个if语句下添加新属性。这样,存储在DB中的信息总是向后兼容的。 它可能不是最好的解决方案,但它对我来说非常有效。