Search code examples
c#.netserializationbinary-serialization

Test for Optional Field when using .NET Custom Serialization


Given a class like this one:

[Serializable]
public class MyClass {
    string name;
    string address;

    public MyClass(SerializationInfo info, StreamingContext context){
        name = info.GetString("name");
        if(/* todo: check if a value for address exists */)
            address = info.GetString("address");
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context){
        info.AddValue(name);
        if(address != null)
            info.AddValue(address);
    }
}

How do I test whether a value for the address field exists before calling info.GetString(address)?

Yes, I do understand that I could simply write a null address field but my real problem is that earlier versions of MyClass, did not have an address field.

Note: I have good reasons for using custom serialization. There are some static fields that are being used as singletons and the default deserialization will not respect that.


Solution

  • Well, one intriguing approach is that you could use GetEnumerator (foreach) to iterate over the name/value pairs, using a switch on the name to handle each in turn?

    The implementation seems a bit non-standard, though; from the example here:

        SerializationInfoEnumerator e = info.GetEnumerator();
        Console.WriteLine("Values in the SerializationInfo:");
        while (e.MoveNext())
        {
            Console.WriteLine("Name={0}, ObjectType={1}, Value={2}",
                 e.Name, e.ObjectType, e.Value);
        }
    

    But it looks like you can also use SerializationEntry:

    [Serializable]
    class MyData : ISerializable
    {
        public string Name { get; set; }
        public int Value { get; set; }
    
        public MyData() { }
        public MyData(SerializationInfo info, StreamingContext context)
        {
            foreach (SerializationEntry entry in info)
            {
                switch (entry.Name)
                {
                    case "Name":
                        Name = (string)entry.Value; break;
                    case "Value":
                        Value = (int)entry.Value; break;
                }
            }
        }
    
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Name", Name);
            info.AddValue("Value", Value);
        }
    }