不总是调用OnSerializing / OnSerialized方法

时间:2012-07-10 20:53:01

标签: c# serialization binaryformatter

这是我在项目中序列化的结构:

[Serializable]
class A : List<B> //root object being serialized

[Serializable]
class B
  + [A few serializable fields]
  + C customList

[Serializable]
class C : List<D>

[Serializable]
class D
  + [several serializable fields]
  |
  + [NonSerialized] nonserializable3rdPartyClass data
  + string xmlOf3rdPartyData
  |
  + [OnSerializing]
  + private void OnSerializing(StreamingContext context)
  |
  + [OnSerialized]
  + private void OnSerialized(StreamingContext context)
  |
  + [OnDeserialized]
  + private void OnDeserialized(StreamingContext context)

nonserializable3rdPartyClass虽然未标记为[Serializable],但却提供了我在.ToXml.FromXml方法中使用的.OnSerializing.OnDeserialized方法分别用于存储和检索xmlof3rdPartyData中的XML字符串。

我最近遇到过一个问题,在某些未知的情况下(我到目前为止只能使用来自客户的序列化数据文件重现问题,首先报告此问题),我的{{1}当使用.OnSerializing序列化到文件时,和.OnSerialized方法只被调用57/160次(其中160是结构中D个对象的总数)将BinaryFormatter设置为D的103 xmlOf3rdPartyData个对象。使用描述here的方法克隆结构时(基本上与我用于序列化文件的方法相同),我看到null / .OnSerializing的结果相同,但我的.OnSerialized方法被称为完整的160次。

这段代码已经使用了好几个月没有问题(至少,据我所知),我仍然试图确定为什么现在发生这种情况而不是更早。我在调试时没有看到任何第一次机会异常,并且我在方法开始时的断点根本没有被击中超过57次。关于为什么会发生这种情况或如何修复它的任何想法?

1 个答案:

答案 0 :(得分:9)

经过几天的挖掘,我发现问题既是我的错也是.NET Framework中可能存在的错误。

.NET的一半问题

在我的OnSerializing方法的堆栈跟踪中,我偶然发现RegisterObject中的System.Runtime.Serialization.SerializationObjectManager方法,它确定是否在对象中调用任何OnSerializing方法被序列化。它以两种方式确定这一点(这是基于.NET Reflector的反编译代码):

  1. 该课程是否有任何OnSerializing方法可供调用
  2. 这是以前看不见的对象(在此BinaryFormatter.Serialize的调用中)
  3. 2号是问题孩子。它通过将它们存储为Hashtable中的对象/布尔对来跟踪已经看到的对象(当然,它使用GetHashCode)。如果其中任何一个为假,则对象的OnSerializing方法被调用。这显然在绝大多数情况下都能正常工作(否则微软会在某些时候修复它,对吧?),除了我似乎偶然发现的那个。

    我的问题的一半

    简单地说,我忘了在我的GetHashCodeD中包含非序列化字段,因此我遇到了冲突。我知道,这个愚蠢的错误不知道我是怎么错过的。

    但等等......

    ......这不是说这根本不是.NET的错,只是我自己的错吗?不,这就是原因。我希望无论如何都会在100%的时间内调用OnSerializingOnSerialized方法。没有文档在哪里说不然。当没有发生这种情况时,我的对象没有正确序列化,最终我花费的时间比想要解决谜团更多。即使两个相同的对象被有目的地序列化,它们显然也不会指向Stream中的相同二进制数据/位置,因此它们不会反序列化。 我认为这是一个错误,而不是一个功能。

    我写了test-case来证明这一切。如果我正在做任何明显错误的事情,我会很感激反馈这样说,否则我可能会在MSDN论坛上发布这个或者作为Connect错误。在有人建议之前,我已经计划在一段时间内从BinaryFormatter切换出来,因为在其他地方发布的所有各种原因,我只是有更重要的事情需要处理。

    修改:显然this bug已在一年半前提交。