.net 二进制序列化,在类中添加一个新字段-它能工作吗?

.net 二进制序列化,在类中添加一个新字段-它能工作吗?,.net,remoting,serialization,binary-serialization,binarystream,.net,Remoting,Serialization,Binary Serialization,Binarystream,我有一个客户端和一个服务器应用程序,它们使用二进制序列化通过.NET2.0远程处理进行通信 对数据传输对象的接口和实现类进行了一个小的更改,添加了一个字符串数组字段 如果我重新部署新版本的服务器应用程序,我的旧客户端是否会继续工作 我想他们会的,因为并没有从接口和直接实现中删除任何内容,但我不确定 这可能归结为另一个问题——二进制反序列化程序是否“足够聪明”以 通过将一个字段初始化为null来处理这种情况,该字段在输入二进制流中找不到数据,或者它将中断并引发异常?很可能它将引发异常,您始终可以通

我有一个客户端和一个服务器应用程序,它们使用二进制序列化通过.NET2.0远程处理进行通信

对数据传输对象的接口和实现类进行了一个小的更改,添加了一个字符串数组字段

如果我重新部署新版本的服务器应用程序,我的旧客户端是否会继续工作

我想他们会的,因为并没有从接口和直接实现中删除任何内容,但我不确定

这可能归结为另一个问题——二进制反序列化程序是否“足够聪明”以
通过将一个字段初始化为null来处理这种情况,该字段在输入二进制流中找不到数据,或者它将中断并引发异常?

很可能它将引发异常,您始终可以通过继承
ISerializable
来实现自己的序列化程序,并通过使用自己的
GetObjectData
方法来实现版本控制……这将使您能够更严格地控制要序列化的数据……下面是一个示例

using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

public class MyFooBar : ISerializable{
    private float _fVersion = 1.0;
    public MyFooBar(SerializationInfo info, StreamingContext context) {
         this._fVersion = info.GetSingle("FooBarVersionID");
         if (this._fVersion == 1.0F) bOk = this.HandleVersionOnePtZero(info, context);
         if (!bOk) throw new SerializationException(string.Format("MyFooBar: Could not handle this version {0}.", this._fVersion.ToString()));
    }
    [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.LinkDemand, Flags = System.Security.Permissions.SecurityPermissionFlag.SerializationFormatter)]
   public void GetObjectData(SerializationInfo info, StreamingContext context) {
       info.AddValue("FooBarVersionID", this._fVersion);
       if (this._fVersion == 1.0F) {
          // Bool's...
          info.AddValue("FooBarBool", FooBarBool);
          // etc... for Version 1.0
       }
       if (this._fVersion == 1.1F){
          // etc... for Version 1.0
       }
   }
}
并在序列化/反序列化时在此上下文中使用MyFooBar,如下所示

public bool Deserialize(string sFileName) {
            bool bSuccessful = false;
            //
            if (!System.IO.File.Exists(sFileName)) return false;
            fuBar = new MyFooBar();
            //
            try {
                using (FileStream fStream = new FileStream(sFileName, FileMode.Open)) {
                    try {
                        BinaryFormatter bf = new BinaryFormatter();
                        fuBar = (MyFooBar)bf.Deserialize(fStream);
                        bSuccessful = true;
                    } catch (System.Runtime.Serialization.SerializationException sEx) {
System.Diagnostics.Debug.WriteLine(string.Format("SERIALIZATION EXCEPTION> DETAILS ARE {0}", sEx.ToString()));
                        bSuccessful = false;
                    }
                }
            } catch (System.IO.IOException ioEx) {
                System.Diagnostics.Debug.WriteLine(string.Format("IO EXCEPTION> DETAILS ARE {0}", ioEx.ToString()));
                bSuccessful = false;
            }
            return (bSuccessful == true);
        }

在2.0+以上版本中,有一种更简洁的方法可以做到这一点,但我更喜欢这种方法。

您可以向新属性添加一个属性:
OptionalField
。如果没有该属性,反序列化程序将无法将序列化数据转换回更新的定义。该属性用于确保反序列化程序能够优雅地处理“缺失”数据

如果要为新属性设置默认值,如果没有反序列化相应的数据,请实现
IDeserializationCallback
接口,并在生成的方法中设置默认值(如果有)