一連のオブジェクトのシリアル化に対処する必要があります。簡単にするために、[Serializable]
属性をバイナリ シリアライザとバイナリ フォーマッタと一緒に使用し[NonSerialized]
、ほとんどのもので不要なフィールドを除外しています。より複雑な部分については、ISerializable
インターフェイス + デシリアライズ コンストラクターを実装しました。これは、循環参照 (通常のオブジェクト参照の形式) がある場合でも、非常にうまく機能します。
今、私は少し混乱する何かにぶつかりました。B
を実装しISerializable
、別のクラス (名前を付けます) によって参照されているContainer
クラスがそのクラスのイベントをサブスクライブすると、シリアライズ時に のGetObjectData
-Method がB
正確に 2 回呼び出されます。
[Serializable]
class Container
{
B subObj;
public int X;
public event EventHandler E;
public Container()
{
subObj = new B(this);
}
}
[Serializable]
class B : ISerializable
{
private Container parent;
public B(Container parent) {
this.parent = parent;
parent.E += (sender, e) => { Console.WriteLine(this.parent.X); };
}
protected B(SerializationInfo info, StreamingContext context) { }
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
Console.WriteLine("GetObjectData");
}
}
したがって、このコード例は次のように記述します
GetObjectData
GetObjectData
循環効果の問題については、スタックオーバーフローか何かを期待していたでしょう:-)。それにもかかわらず、良くありません。もちろん、この例の回避策は、逆シリアル化コンストラクターにイベントを再度追加することです。しかし、私はこれを引き起こした原因を突き止めたいと思います。
最後に 1 つ: 上記のラムダ式の参照を次のように変更すると (フィールドではなくパラメーターを参照する)...
parent.E += (sender, e) => { Console.WriteLine(parent.X); };
... シリアライゼーションは、初回実行直後にSerializationException
( B+<>c__DisplayClass2 is not mark as SerializableGetObjectData
) でクラッシュします。
理由のヒント (および有用な回避策) を歓迎します。