Serializing events with circular references using ISerializable

171 views Asked by At

I have to deal with serializing a bunch of objects. For the sake of simplicity I am using the [Serializable] attribute together with the binary serializer and binary formatter, excluding non-neccessary fields with [NonSerialized] for most of the stuff. For the more complex parts I implemented the ISerializable interface + a deserializing constructor. This works quite well, even when having circular references (in the form of normal object references).

Now I stubled over something that confuses me a bit. When a class B implementing ISerializable, and beeing referenced by another class (lets name it Container) subscribes to an event of that class, the GetObjectData-Method of B is called exactly twice when serializing.

[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");
    }
}

So this example code writes

GetObjectData
GetObjectData

For a problem with circular effects I'd have rather expected a stack overflow or something :-). Not good nonetheless. A workaround for this example would of course be re-adding the event in the deserializing constructor. But I'd like to get behind what causes this.

One last thing: If one changes the reference in the lambda expression above to the following (referencing the parameter, not the field)...

parent.E += (sender, e) => { Console.WriteLine(parent.X); };

... serialization crashes with an SerializationException (B+<>c__DisplayClass2 is not marked as Serializable) right after the first time GetObjectData is executed.

Any hints for why (as well as useful workarounds) appreciated.

0

There are 0 answers