11

プロジェクトでシリアル化する構造は次のとおりです。

[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、としてマークされていませんが、XML文字列をに格納および取得するためにそれぞれmyおよびmethodsで使用するメソッドを提供し[Serializable]ます。.ToXml.FromXml.OnSerializing.OnDeserializedxmlof3rdPartyData

最近、特定の不明な状況(これまで、問題を最初に報告したクライアントからのシリアル化されたデータファイルを使用してのみ問題を再現できた)で、myメソッド.OnSerializing.OnSerializedメソッドが呼び出されるだけの問題に遭遇しました57 / 160回(160はD構造内のオブジェクトの総数)を使用BinaryFormatterしてファイルにシリアル化すると、103D個のオブジェクトがにxmlOf3rdPartyData設定されたままになりnullます。ここで説明する方法(基本的にはファイルへのシリアル化に使用する方法と同じです)を使用して構造を複製すると、 .OnSerializing/についても同じ結果が表示されます.OnSerializedが、私の.OnDeserialized方法は完全な160回呼び出されます。

このコードは何ヶ月も問題なく使用されており(少なくとも私が知る限り)、なぜこれが以前ではなく今起こっているのかを突き止めようとしています。デバッグ中に最初のチャンスの例外は表示されません。また、メソッドの先頭にあるブレークポイントが57回を超えてヒットしていません。なぜこれが発生するのか/それを修正する方法についてのアイデアはありますか?

4

1 に答える 1

10

数日間掘り下げた後、問題は私のせいであり、.NETFrameworkのバグの可能性があることを発見しました。

問題の.NETの半分

メソッドのスタックトレースを調べているときに、シリアル化されているオブジェクトのメソッドを呼び出すかどうかを決定するのメソッドにOnSerializing出くわしました。これは2つの方法で決定されます(これは.NET Reflectorから逆コンパイルされたコードに基づいています)。RegisterObjectSystem.Runtime.Serialization.SerializationObjectManagerOnSerializing

  1. クラスにはOnSerializing呼び出すメソッドがありますか
  2. これは以前は見られなかったオブジェクトですか(この呼び出し内でBinaryFormatter.Serialize

2番目は問題の子です。オブジェクト/ブールペアとして(もちろんHashtable使用します)に格納することにより、すでに表示されているオブジェクトを追跡します。GetHashCodeこれらのいずれかがfalseの場合、オブジェクトのOnSerializingメソッドは呼び出されません。これは、私が偶然見つけたものを除いて、ほとんどの状況でうまく機能しているようです(そうでなければ、Microsoftはある時点で修正していたでしょう?)。

問題の私の半分

GetHashCode簡単に言うと、クラスのシリアル化できないフィールドを含めるのを忘れたため、D衝突が発生していました。愚かな間違い、私は知っている、私がそれをどのように逃したのかわからない。

ちょっと待って...

...それは、それが.NETのせいではなく、私自身のせいであるという意味ではないでしょうか。いいえ、その理由は次のとおりです。OnSerializing私は、OnSerializedメソッドが何があっても100%呼び出されることを期待しています。ドキュメントのどこにそれ以外のことは書かれていません。それが起こらないと、私のオブジェクトは正しくシリアル化されず、謎を解こうとするよりもずっと多くの時間を費やすことになります。2つの同一のオブジェクトが意図的にシリアル化されている場合でも、それらは明らかに、内の同じバイナリデータ/場所を指しているStreamわけではないため、同じものを逆シリアル化することはありません。これは機能ではなくバグだと思います。

これらすべてを実証するテストケースを作成しました。露骨に間違ったことをしている場合は、フィードバックをいただければ幸いです。そうでない場合は、MSDNフォーラムに投稿するか、Connectのバグとして投稿します。そして、誰かが提案する前に、私はBinaryFormatterSOの他の場所に投稿されたさまざまな理由から、しばらくの間から切り替えることを計画していましたが、対処すべきもっと重要なことがあります。

編集:どうやらこのバグは1年半以上前に提出されました。

于 2012-07-13T01:09:09.817 に答える