views:

107

answers:

1

What's going on behind the scenes in .NET (de)serialization that makes it behave the way it does in the following scenario? (This is a test app that just illustrates my setup.)

I have a class with a NameValueCollection property:

[Serializable]
public class MyClassWithNVC
{
    public NameValueCollection NVC { get; set; }
}

It, in turn, is contained in another class:

[Serializable]
class Wrapper : ISerializable
{
    public MyClassWithNVC MyClass { get; private set; }

    public Wrapper()
    {
        MyClass = new MyClassWithNVC
                      {
                          NVC = new NameValueCollection
                                    {
                                        {"TestKey", "TestValue"}
                                    }
                      };
    }

    public Wrapper(SerializationInfo info, StreamingContext context)
    {
        MyClass = info.GetValue("MyClass", typeof(MyClassWithNVC)) as MyClassWithNVC;

        if(MyClass.NVC == null)
        {
            Console.WriteLine("NVC is null inside Wrapper's ctor.");
        }
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("MyClass", MyClass);
    }
}

My test program is below:

class Program
{
    static void Main(string[] args)
    {
        using(MemoryStream ms = new MemoryStream())
        {
            Wrapper wrapper = new Wrapper();
            new BinaryFormatter().Serialize(ms, wrapper);

            ms.Seek(0, SeekOrigin.Begin);

            Wrapper loaded = new BinaryFormatter().Deserialize(ms) as Wrapper;
            if(loaded.MyClass.NVC.Count == 1 && loaded.MyClass.NVC[0] == "TestValue")
            {
                Console.WriteLine("NVC is not null after Wrapper's ctor and has the correct value.");
            }
        }

        Console.ReadKey();
    }
}

When I run it, I see the following printed out in the console:

NVC is null inside Wrapper's ctor.

NVC is not null after Wrapper's ctor and has the correct value.

What's going on here? The NameValueCollection is obviously capable of deserializing itself with the default serialization, but why is that deserialization delayed and not happening at the GetValue() call in the Wrapper's constructor?

+1  A: 

I tried to dig a bit in the Deserialize method without finding out exact how it's implemented.

It seems it will first run the ISerializable code implementations. Once all custom code has finished it will deserialize all automatically serialized objects (like your MyClassWithNVC class in the sample).

If you let MyClassWithNVC inherit from ISerializable then it runs your custom deserialization code, and MyClass.NVC is not NULL in the Wrapper deserializer method.

So it's not specific behavior to NameValueCollection, but any property which is automatically serialized.

Mikael Svenson
@Mikael: Thanks for the reply. This still seems weird. Why wouldn't both kinds of serialization be processed during the GetValue() call? I also cannot reproduce the same behaviour with another class, but I'll keep trying.
Anna Lear
Ah, figured it out. The key is the IDeserializableCallback that NameValueCollection implements. So this issue can be reproduced with any collection (or object) that does the same. More details towards the bottom of the page here: http://msdn.microsoft.com/en-us/library/ms973893.aspx
Anna Lear
The MSDN documentation seems to have it all if we just read it close enough :) Thanks for linking to that page. I'm a bit wiser as well.
Mikael Svenson