Почему атрибут NonSerialized нельзя использовать на уровне класса?Как предотвратить сериализацию класса?

StackOverflow https://stackoverflow.com/questions/2467376

Вопрос

У меня есть объект данных, который глубоко клонирован с использованием двоичной сериализации.Этот объект данных поддерживает события изменения свойств, например PriceChanged.

Допустим, я прикрепил обработчик к PriceChanged.Когда код пытается сериализовать PriceChanged, он выдает исключение, что обработчик не помечен как сериализуемый.

Мои альтернативы:

  • Я не могу легко удалить все обработчики события перед сериализацией.
  • Я не хочу помечать обработчик как сериализуемый, потому что мне пришлось бы также рекурсивно отмечать все зависимости обработчиков.
  • Я не хочу помечать PriceChanged как NonSerialized — существуют десятки подобных событий, которые потенциально могут иметь обработчики.РЕДАКТИРОВАТЬ:Другая причина, по которой я не могу этого сделать, заключается в том, что классы данных (и, следовательно, события) генерируются, и у меня нет прямого контроля над кодом генерации.В идеале код генерации просто помечал бы все события как NonSerialized.
  • В идеале я бы хотел, чтобы .NET просто прекратил движение вниз по графу объектов в этой точке и превратил его в «лист». Так почему же .NET не позволяет пометить весь класс как NonSerialized?

--

В конце концов я решил эту проблему, заставив обработчик реализовывать ISerializable и ничего не делая в конструкторе сериализации/методе GetDataObject.Но обработчик по-прежнему сериализуется, просто для всех его зависимостей установлено значение null, поэтому мне тоже пришлось это учитывать.

Есть ли лучший способ предотвратить сериализацию всего класса? То есть тот, который не требует учета нулевых зависимостей?

Это было полезно?

Решение

Хотя я склонен не согласиться с таким подходом (я бы просто пометил события как несериализованные, независимо от их количества), вы, вероятно, могли бы сделать это, используя суррогаты сериализации.

Идея состоит в том, что вы создаете объект, который реализует ISerializationSurrogate и по сути делает то, что вы уже делаете — ничего в методах GetObjectData и SetObjectData.Разница в том, что вам придется настраивать сериализацию делегата, а не содержащего его класса.

Что-то вроде:

class DelegateSerializationSurrogate : ISerializationSurrogate {
    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) {
        // do nothing
    }
    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context) {
        // do nothing
        return null;
    }
}

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

Другие советы

...есть десятки событий...

Лично я бы просто добавил несериализованные маркеры, что для событий, подобных полям, проще всего сделать с помощью:

[field: NonSerialized]
public event SomeEventType SomeEventName;

(вам не нужно добавлять делегата поддержки вручную)

Каковы ваши требования к сериализации? BinaryFormatter во многих отношениях наименее дружелюбный из сериализаторов;последствия для событий немного неприятны, и при хранении он очень хрупкий (ИМО, он действительно подходит только для транспортировки, а не для хранения).

Однако;существует множество хороших альтернатив, которые поддерживают наиболее распространенные сценарии «глубокого клонирования»:

  • XmlSerializer (но только для публичных участников)
  • DataContractSerializer / NetDataContractSerializer
  • protobuf-net (который включает в себя Serializer.DeepClone для этой цели)

(обратите внимание, что в большинстве случаев для поддержки сериализации потребуются дополнительные атрибуты, что не сильно отличается от добавления [NonSerialized] атрибуты на первом месте!)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top