二进制序列化,向类添加新字段 - 它会起作用吗?

发布于 2024-09-15 00:32:19 字数 283 浏览 5 评论 0原文

我有一个客户端和一个服务器应用程序,它们使用二进制序列化通过 .NET 2.0 Remoting 进行通信。

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

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

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

它可能归结为另一个问题 - 二进制反序列化器是否“足够聪明” 通过初始化一个字段来处理这样的情况,它无法在输入二进制流中找到数据为空,或者它会中断并抛出异常吗?

I have a client and a server application which communicate over .NET 2.0 Remoting using binary serialization.

A small change has been made to one of the data transfer object's interface and the implementing class, well, an array of strings field was added.

If I to redeploy a new version of server application, will my old clients continue to work?

I would think they would, since nothing has been deleted from interface and direct implementation, but I am not sure.

It probably boils down to another question - is a binary deserialiser "clever enough" to
handle the situation like this by initializing a fields it fails to find data in the input binary stream to null, or is it going to break and to throw the exception?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

朦胧时间 2024-09-22 00:32:19

您可以向新属性添加属性:OptionalField。如果没有该属性,反序列化器将无法将序列化数据转换回更新的定义。该属性是为了确保解串器能够优雅地处理“丢失”的数据。

如果要为新属性设置默认值,在没有反序列化适当数据的情况下,请实现 IDeserializationCallback 接口,并在结果方法中设置默认值(如果有) 。

You can add an attribute to the new property: OptionalField. Without the attribute, the deserializer will not be able to convert serialized data back to the updated definition. The attribute is to ensure the deserializer can handle the "missing" data gracefully.

If you want to set a default value for the new property, in the case that no appropriate data for it is deserialized, implement the IDeserializationCallback interface, and set the default value, if any, in the resulting method.

只是在用心讲痛 2024-09-22 00:32:19

它很可能会抛出异常,您始终可以通过继承 ISerialized 来实现自己的序列化器,并使用您自己的 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+ 以上版本中,有一种更简洁的方法可以做到这一点,但我更喜欢这种方式。

More than likely it is going to throw an exception, you could always implement your own Serializer by inheriting from ISerializable and implement the versioning by using your own methods of GetObjectData...this will give you a tighter degree of control over the data to be serialized...Here's an example

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
       }
   }
}

And use MyFooBar in this context when serializing/deserializing as shown below

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

There is a more neater way to do this in 2.0+ upwards, but I prefer this way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文