views:

54

answers:

2

I have object A and object B deserialized from binary files. B has a private method which is used as a callback function and does some manipulation on a private data member when A raise an event. To clarify the basic structure:

Class A
{
    private static A instance;
    public static A GetInstance(){...};
    private A(){}

    public delegate void SomeCallback(Arg a);
    public event SomeCallback doCallback;

    ...
}

Class B
{
    private Dictionary<., .> dict;

    public B()
    {
        A.GetInstance().doCallback += new A.SomeCallback(ManipulateDict);
        ...
    }

    private void ManipulateDict(Arg a){...} //breakpoint here

    public void PrintDict(){...}        
}

After A and B is deserialized, whenever A raise event doCallback, I can see the breakpoint line(ManipulateDict) will be executed as I'm expecting. However, the strange thing is, it will manipulate on a 'dict' which has a different memory address with the object's, which means, even if ManipulateDict 'successfully' updated some data in dict, the other methods, say, PrintDict, still don't see the changes in dict.
If I don't use serialization, this won't happen and it behaves just right. But as serialization is introduced to this program, things goes weird. Am I doing something wrong? Who can explain this?

Thank you very much!

A: 

What method of serialization are you using? I suspect that you are using something like XMLSerializer which is creating a new copy of each object every time it appears in the object graph. This means that you get multiple independent copies of the object when you deserialize. If you use SoapFormatter instead you should get just one object, which will solve the problem.

Update: Most deserialization methods call the default constructor. Your default constructor is creating new objects. This could also be a problem.

Mark Byers
Hi. I'm using BinaryFormatter.
fwoncn
I think part of the problem is your use of singletons. Each time you create a B, it adds a new event handler to A, but you aren't removing these event handlers again.
Mark Byers
No. Actually B is a singleton, too. I write the code snippet this way for simplicity. Sorry for not mentioning that.
fwoncn
+1  A: 

I would think that when you serialize B, it preserves the memory location of the original A.SomeCallback. When you deserialize A, the reconstituted object is now in a different location, and so SomeCallback is in a new location as well. The deserialized B is still calling SomeCallback in the old A location which would still be referring to the original data. Maybe you need to re-connect the delegate after deserialization.

Ray
Sounds like your explanation make sense to me. I tried again but still not fixed it. Could you please tell me more about how to re-connect the delegate. I just add a line the same with that in B's constructor.
fwoncn
I would suggest a method in B that you can call after you deserialize. Pass the freshly deserialized A to the method, and add the delegate as you already know how to do. If my theory is correct, you may need to remove the original delegate so both the orginal and new copies of SomeCalback do not get called.
Ray
Bingo!!! Ray, thank you so much!!! Really really appreciate it. And one more thing: clear all the necessary delegates before serialize B, or A will gain more and more deaf subscribers.
fwoncn