【问题标题】:versioning serialization in c# when using iserializable interface使用可序列化接口时在 C# 中的版本控制序列化
【发布时间】:2014-04-14 07:38:05
【问题描述】:

我有一个基类 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

所以我正在寻找在使用可序列化接口时在版本化序列化 c# 方向上的任何建议,这样即使我们向类中添加新字段时它也不会中断。提前感谢您的帮助。

【问题讨论】:

    标签: c# serialization


    【解决方案1】:

    最后我找到了解决方案.. 但是它不使用 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 语句下添加新属性。这样存储在数据库中的信息总是向后兼容的。 这可能不是最好的解决方案,但它对我来说非常有效。

    【讨论】:

    • 提示:您可以使用类 System.Version 而不是 int
    猜你喜欢
    • 2020-09-14
    • 2011-03-12
    • 2013-03-15
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    • 2011-12-25
    • 1970-01-01
    相关资源
    最近更新 更多