двоичная сериализация, добавление нового поля в класс - это будет работать? - PullRequest
4 голосов
/ 20 августа 2010

У меня есть клиентское и серверное приложение, которое взаимодействует через .NET 2.0 Remoting с использованием двоичной сериализации.

Небольшое изменение было внесено в один из интерфейса объекта передачи данных, и реализующий класс, ну, в общем, было добавлено поле массива строк.

Если я переустановлю новую версию серверного приложения, мои старые клиенты продолжат работать?

Я бы подумал, что это так, поскольку ничего не было удалено из интерфейса и прямой реализации, но я не уверен.

Это, вероятно, сводится к другому вопросу - является ли бинарный десериализатор "достаточно умным", чтобы обработать ситуацию, подобную этой, путем инициализации полей, в которых не удается найти данные во входном двоичном потоке в нулевое значение, или он собирается сломаться и вызвать исключение?

Ответы [ 2 ]

4 голосов
/ 20 августа 2010

Вы можете добавить атрибут к новому свойству: OptionalField. Без атрибута десериализатор не сможет преобразовать сериализованные данные обратно в обновленное определение. Атрибут должен гарантировать, что десериализатор может корректно обрабатывать «пропущенные» данные.

Если вы хотите установить значение по умолчанию для нового свойства, в случае, если никакие соответствующие данные для него не десериализованы, реализуйте интерфейс IDeserializationCallback и установите значение по умолчанию, если оно есть, в результирующем методе.

0 голосов
/ 20 августа 2010

Скорее всего, это вызовет исключение, вы всегда можете реализовать свой собственный Serializer, унаследовав от 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 в этом контексте при сериализации / десериализации, как показано нижеспособ сделать это в 2.0+ и выше, но я предпочитаю этот способ.

...