views:

337

answers:

4

Lets say I have classA which contains classB and both are [Serializable].

I assumed, that on Deserialization classB would be deserialized first.

This is not the case however, as I could confirm by just logging when each [OnDeserialized] methods were hit.

Now I have the following issue:

After classA's deserialization is complete, it is supposed to set itself up, using values from classB. Unfortunately, classB has not been deserialized yet at this point, so classA gets set up wrong.

My problem would be solved, if I could force the BinaryFormatter to deserialize classB before classA, or resolve the Object Graph bottom to top instead of top to bottom.

Another obvious solution would be to make classB fire an event when it is deserialized and then have classA set itself up, but I want to stay away from this non-elegant workaround.

So I would appreciate if somebody knows of a better solution.

A: 

I would suggest to just used a method marked with [OnDeserialized] to handle any post-serialization initialization you require and not concern yourself with the order in which they are deserialized.

Programming Hero
I don't know if you understood my question correctly, as it explains, that I do need to concern myself with the deserialization order because my objects don't get restored correctly otherwise.
Thorsten Lorenz
Obviously I must have. Can you explain exactly what needs to happen between A and B which cannot be handled by an post-serialization event?
Programming Hero
The details do not matter, I think I explained it clearly enough:"After classA's deserialization is complete, it is supposed to set itself up, using values from classB."These values are only set once classB has been completely deserialized.
Thorsten Lorenz
+1  A: 

If you have to have explicit control over the order of your objects serialization and deserialization, I suggest you implement the ISerializable interface for A:

public class ClassA : ISerializable
{
    private ClassB _dependency;

    public ClassA(SerializationInfo information, StreamingContext context)
    {
        _dependency 
            = (ClassB)information.GetValue("_dependency", typeof(ClassB));

        // TODO: Get other values from the serialization info.
        // TODO: Set up stuff from dependent object.
    }

    public SerializationInfo GetObjectData()
    {
        information.AddValue("_dependency", _dependency, typeof(ClassB));

        // TODO: Add other fields to the serialization info.
    }
}
Programming Hero
Thank you, that would work. The only disadvantage is, that in order to do that one little tweak (change the deserialization order), I have to manually get all the other objects/fields on my class as well.In the meantime I used the not so elegant solution (via event firing) as described in my question.I guess I'll stick with it, as this workaround seems still simpler than the verbose solution of getting the object data by hand.
Thorsten Lorenz
A: 

These two steps might do the trick:

  1. Make the [OnDeserialized] method of classB safe to call multiple times.
  2. In the [OnDeserialized] method of classA, explicitly call the [OnDeserialized] method on the contained classB object.

The BinaryFormatter will end up calling the [OnDeserialized] method on the classB object again, but step 1 makes that safe.

Wesley Hill
A: 

You could make classA implement the IDeserializationCallback interface. Its OnDeserialization method will only be called one the entire object graph has been deserialized, including the classB object.

Wesley Hill