7

MSDN がここで述べているように、可能です。しかし、mscorlib コードを掘り下げるのに 2 時間を費やしました。場合によっては、BinaryFormatter が OnDeserialized BEFORE デシリアライゼーション コンストラクターでマークされたメソッドを呼び出したからです。つまり、注文は

OnDeserializing(StreamingContext context)
OnDeserialized(StreamingContext context)
.ctor(SerializationInfo info, StreamingContext context)

そうなることを期待しながら

OnDeserializing(StreamingContext context)
.ctor(SerializationInfo info, StreamingContext context)
OnDeserialized(StreamingContext context)

そして最後のポイント。IDeserializationCallback インターフェイスを実装したとき、そのメソッド OnDeserialization は、私が望んでいて期待したとおり、AFTER コンストラクターと呼ばれていました。

これをいくつかの単純なクラス構造で再現しようとしましたが、すべてうまくいきました。私たちのプロジェクトでは、シリアル化されているオブジェクト グラフが非常に複雑なので、どこを掘ればよいかわかりません。mscorlib コードをリフレクターで調べてもあまり役に立ちませんでした。逆シリアル化コードが複雑すぎて、問題の原因を突き止めることができませんでした。

それで、誰がそのような問題を引き起こしているのか知っていますか? OnDeserialized が他のいくつかの場所でコンストラクターの前に呼び出されるという前提を使用しているため、信頼性が低いのではないかと心配しています...

ありがとう!

4

1 に答える 1

6

最後に、誰かが興味を持っているかどうか、私自身の質問に対する答えがあります。この記事の最後にある例を考えてみましょう。2 つのクラスがあり、そのインスタンスには相互参照が含まれています。このような状況では、両方のインスタンスのデシリアライズ コンストラクターが構築されたオブジェクトと共に渡される可能性はありません。したがって、シリアライザーは最初にコンストラクターの 1 つを呼び出して、2 番目の型の構築されていないインスタンスを渡し、次にそのオブジェクトのコンストラクターを呼び出して、最初の型の構築されたインスタンスを渡します。このように、オブジェクトの接続を復元するのに役立つので、これができるのは本当に最高です!

次に、そのような場合のコールバックは、質問で指摘したように呼び出される可能性がありますがOnDeserializing、仕様に記載されているとおり、COMPLETE オブジェクト グラフが逆シリアル化された後に常にメソッドが呼び出されます。OnDeserializedOnDeserializationIDeserializationCallback

上記のすべてを念頭に置いて、IDeserializationCallbackインターフェイスを使用して、必要なデシリアライゼーション後の処理を行うのが最善だと思います。その場合、すべてのオブジェクトに対してコンストラクターが呼び出され、必要な変更を「安全な」方法で行うことができると確信しています。

      [Serializable]
      class One :ISerializable, IDeserializationCallback
      {
           public Two m_two;
           public One() {}
           public One(SerializationInfo info, StreamingContext context)
           {
                var two = (Two)info.GetValue("m_two", typeof(Two));
                m_two = two;
           }
           public void GetObjectData(SerializationInfo info, StreamingContext context)
           {
                info.AddValue("m_two", m_two);
           }
           private bool m_onDeserializing;
           private bool m_onDeserialized;
           private bool m_callback;
           public void OnDeserialization(object sender)
           {
                m_callback = true;
           }
           [OnDeserializing]
           void OnDeserializing(StreamingContext context)
           {
                m_onDeserializing = true;
           }

           [OnDeserialized]
           void OnDeserialized(StreamingContext context)
           {
                m_onDeserialized = true;
           }
      }

      [Serializable]
      private class Two : ISerializable, IDeserializationCallback
      {
           public Two(){}
           public One m_one;
           public Two(SerializationInfo info, StreamingContext context)
           {
                var one = (One)info.GetValue("m_one", typeof(One));
                m_one = one;
           }
           public void GetObjectData(SerializationInfo info, StreamingContext context)
           {
                info.AddValue("m_one", m_one);
           }
           private bool m_onDeserializing;
           private bool m_onDeserialized;
           private bool m_callback;
           public void OnDeserialization(object sender)
           {
                m_callback = true;
           }
           [OnDeserializing]
           void OnDeserializing(StreamingContext context)
           {
                m_onDeserializing = true;
           }
           [OnDeserialized]
           void OnDeserialized(StreamingContext context)
           {
                m_onDeserialized = true;
           }
      }

      [STAThread]
      static void Main()
      {
           var one = new One();
           one.m_two = new Two();
           one.m_two.m_one = one;

           BinaryFormatter formatter = new BinaryFormatter();
           MemoryStream mss =new MemoryStream();
           formatter.Serialize(mss, one);
           mss.Position = 0;
           var deserialize = formatter.Deserialize(mss);
      }
于 2012-01-16T11:28:52.620 に答える