为什么不能在类级别使用“NonSerialized”属性?如何防止类的序列化?
-
20-09-2019 - |
题
我有一个使用二进制序列化进行深度克隆的数据对象。该数据对象支持属性更改事件,例如 PriceChanged。
假设我将一个处理程序附加到 PriceChanged。当代码尝试序列化 PriceChanged 时,它会引发异常,表明处理程序未标记为可序列化。
我的替代方案:
- 在序列化之前,我无法轻松地从事件中删除所有处理程序
- 我不想将处理程序标记为可序列化,因为我还必须递归地标记所有处理程序依赖项。
- 我不想将 PriceChanged 标记为 NonSerialized - 有数十个这样的事件可能有处理程序。编辑:我不能这样做的另一个原因是因为数据类(以及事件)是生成的,并且我无法直接控制生成代码。理想情况下,生成代码只会将所有事件标记为 NonSerialized。
- 理想情况下,我希望 .NET 在此时停止沿着对象图向下移动,并将其设为“叶子”。 那么为什么 .NET 不允许将整个类标记为 NonSerialized?
--
我最终通过使处理程序实现 ISerialized 并在序列化构造函数/ 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
从很多方面来说,它是序列化器中最不友好的;对事件的影响有点难看,如果存储的话它会非常脆弱(IMO 它只适合运输,而不适合存储)。
然而;有很多好的替代方案可以支持最常见的“深度克隆”场景:
XmlSerializer
(但仅限公众会员)DataContractSerializer
/NetDataContractSerializer
- protobuf-net(其中包括
Serializer.DeepClone
以此目的)
(请注意,在大多数序列化支持中都需要额外的属性,因此与添加 [NonSerialized]
首先是属性!)