为什么不能在类级别使用'NonSerialized'属性?如何防止类的序列化?

时间:2010-03-18 03:20:55

标签: c# binary-serialization nonserializedattribute

我有一个使用二进制序列化进行深度克隆的数据对象。此数据对象支持属性更改事件,例如,PriceChanged。

假设我将处理程序附加到PriceChanged。当代码尝试序列化PriceChanged时,它会抛出一个异常,即处理程序未标记为可序列化。

我的替代方案:

  • 我无法在序列化之前轻松删除事件中的所有处理程序
  • 我不想将处理程序标记为可序列化,因为我还必须递归地标记所有处理程序依赖项。
  • 我不想将PriceChanged标记为NonSerialized - 有这样的数十个事件可能有处理程序。编辑:我不能这样做的另一个原因是因为生成了数据类(以及事件),并且我无法直接控制生成代码。理想情况下,生成代码只会将所有事件标记为NonSerialized。
  • 理想情况下,我希望.NET能够在此时停止对象图并使其成为“叶子”。 那么为什么.NET不允许将整个类标记为NonSerialized?

-

我终于通过使处理程序实现ISerializable并在serialize构造函数/ GetDataObject方法中不执行任何操作来解决此问题。但是,处理程序仍然是序列化的,只是将其所有依赖项设置为null - 所以我也必须考虑到这一点。

有没有更好的方法来阻止整个类的序列化?那就是,不需要考虑空依赖关系?

2 个答案:

答案 0 :(得分:4)

虽然我倾向于不同意这种方法(我只是将事件标记为NonSerialized,无论有多少),你可以使用序列化代理来做到这一点。

这个想法是你创建一个实现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;
    }
}

然后使用程序outlined in this MSDN column向格式化程序注册。然后,只要格式化程序遇到委托,它就会使用代理而不是直接序列化委托。

答案 1 :(得分:2)

  

......有几十个事件......

就个人而言,我只是添加非序列化标记,这些标记最容易通过以下方式完成:

[field: NonSerialized]
public event SomeEventType SomeEventName;

(您无需添加手动支持代理)

您的序列化要求到底是什么? BinaryFormatter在许多方面是序列化程序中最不友好的;对事件的影响有点难看,如果存储它会非常脆弱(IMO它只适合运输而不是存储)。

然而;有很多很好的选择可以支持最常见的“深度克隆”场景:

  • XmlSerializer(但仅限于公开会员)
  • DataContractSerializer / NetDataContractSerializer
  • protobuf-net(为此目的包括Serializer.DeepClone

(请注意,在大多数序列化支持中,需要额外的属性,因此首先添加[NonSerialized]属性没有太大区别!)