【问题标题】:Why can't the 'NonSerialized' attribute be used at the class level? How to prevent serialization of a class?为什么不能在类级别使用“NonSerialized”属性?如何防止类的序列化?
【发布时间】:2010-03-18 03:20:55
【问题描述】:

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

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

我的替代方案:

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

--

我最终通过使处理程序实现 ISerializable 并且在序列化构造函数/GetDataObject 方法中什么都不做来解决这个问题。但是,处理程序仍然是序列化的,只是它的所有依赖项都设置为 null - 所以我也必须考虑到这一点。

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

【问题讨论】:

    标签: c# binary-serialization nonserializedattribute


    【解决方案1】:

    虽然我倾向于不同意这种方法(我只是将事件标记为 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 将其注册到格式化程序。然后,每当格式化程序遇到委托时,它都会使用代理而不是直接序列化委托。

    【讨论】:

    • 感谢您向我介绍序列化代理的想法。我喜欢它——至少我不必“污染”原始数据类。不过有一件事 - 我还没有尝试过,但我怀疑我仍然会遇到空依赖问题?
    • 我不这么认为。由于您将拦截委托的序列化并有效地取消它,因此处理程序根本不会被序列化。
    【解决方案2】:

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

    就个人而言,我只需添加非序列化标记,对于类似字段的事件,最容易通过以下方式完成:

    [field: NonSerialized]
    public event SomeEventType SomeEventName;
    

    (您不需要添加手动支持委托)

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

    但是;有很多好的替代方案可以支持最常见的“深度克隆”场景:

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

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

    【讨论】:

    • 要求是支持不断发展的数据对象的深度克隆,即从发布到发布的新字段/属性。我已经在上面提到了为什么标记字段 NonSerialized 并不是一个真正的选择。
    猜你喜欢
    • 2012-09-21
    • 1970-01-01
    • 2011-08-13
    • 1970-01-01
    • 1970-01-01
    • 2017-05-09
    • 1970-01-01
    • 2011-09-23
    • 1970-01-01
    相关资源
    最近更新 更多