c# - 使用可序列化接口(interface)时在 C# 中进行版本控制序列化

标签 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

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

最佳答案

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

关于c# - 使用可序列化接口(interface)时在 C# 中进行版本控制序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23054513/

相关文章:

c# - 如何有效地计算移动标准偏差

c# - 反序列化来自 Json Http 响应的对象列表

c# - 将值从字符串转换为流时出错

c# - 如何将字符串中的 [city] 替换为 [City]

c# - 使用 ADAL JS 的 Azure AD Graph API 不记名 token

c# - Java TCP 客户端不接收从 C# 服务器发送的消息

.net - 如何重构在 .NET 中序列化的类?

c# - c# 最快的序列化机制是什么?

c# - 在 Web API Controller 中接收 Json 反序列化对象作为字符串

c# - C# 8 中的默认接口(interface)方法