Почему нельзя использовать атрибут NonSerialized на уровне класса? Как предотвратить сериализацию класса?
У меня есть объект данных, который глубоко клонируется с помощью двоичной сериализации. Этот объект данных поддерживает события изменения свойств, например PriceChanged.
Допустим, я прикрепил обработчик к PriceChanged. Когда код пытается сериализовать PriceChanged, он выдает исключение, что обработчик не помечается как сериализуемый.
Мои альтернативы:
- Я не могу легко удалить все обработчики из события до сериализации
- Я не хочу помечать обработчик как сериализуемый, потому что мне нужно было бы также рекурсивно пометить все зависимости обработчиков.
- Я не хочу отмечать PriceChanged как NonSerialized - существуют десятки подобных событий, которые потенциально могут иметь обработчики. РЕДАКТИРОВАТЬ: Еще одна причина, почему я не могу сделать это, потому что классы данных (и, следовательно, события) генерируются, и я не имею прямого контроля над кодом генерации. В идеале код генерации должен просто пометить все события как несериализированные.
- В идеале я бы хотел, чтобы.NET просто прекратил спускаться по графу объектов в этот момент и сделал это "листом". Так почему же.NET не позволяет пометить весь класс как несериализуемый?
-
В конце концов я обошел эту проблему, заставив обработчик реализовать ISerializable и ничего не делая в методе serialize constructor/ GetDataObject. Но обработчик по-прежнему сериализован, просто со всеми его зависимостями, установленными в нуль - так что я должен был это учитывать.
Есть ли лучший способ предотвратить сериализацию всего класса? То есть тот, который не требует учета нулевых зависимостей?
2 ответа
Хотя я склонен не соглашаться с подходом (я бы просто пометил события как несериализированные, независимо от их количества), вы, вероятно, могли бы сделать это с помощью суррогатов сериализации.
Идея состоит в том, что вы создаете объект, который реализует 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
во многих отношениях наименее дружелюбный из сериализаторов; последствия для событий немного уродливы, и при хранении они очень хрупкие (IMO действительно подходит только для транспортировки, а не для хранения).
Тем не мение; Есть много хороших альтернатив, которые поддерживали бы наиболее распространенные сценарии "глубокого клонирования":
XmlSerializer
(но только для публичных участников)DataContractSerializer
/NetDataContractSerializer
- Protobuf-сеть (которая включает в себя
Serializer.DeepClone
для этого)
(обратите внимание, что в большинстве случаев для поддержки сериализации потребуются дополнительные атрибуты, поэтому они не сильно отличаются от добавления [NonSerialized]
атрибуты на первом месте!)