Question

As I understand it I have to adorn a new member in a newer version of my class with the [OptionalField] Attribute when I deserialize an older version of my class that lacks this newer member.

However, the code below throws no exception while the InnerTranslator property was added after serializing the class. I check for the property to be null in the onDeserialization method (which confirms that it was not serialized),but I would have expected the code to throw an exception because of that. Is the [OptionalField] Attribute itself optional?

class Program
{
    static void Main(string[] args)
    {
        var listcol = new SortedList<string,string>
        {
            {"Estados Unidos", "United States"},
            {"Canadá", "Canada"},
            {"España", "Spain"}
        };
        var translator = new CountryTranslator(listcol);
        using (var file_stream=new FileStream("translator.bin",FileMode.Open))
        {
            var formatter = new BinaryFormatter();
            translator = formatter.Deserialize(file_stream) as CountryTranslator;
            file_stream.Close();
        }
        Console.ReadLine();
    }
}

[Serializable]
internal class CountryTranslator:IDeserializationCallback
{
    public int Count { get; set; }

    public CountryTranslator(SortedList<string,string> sorted_list)
    {
        this.country_list = sorted_list;
        inner_translator = new List<string> {"one", "two"};
    }
    //[OptionalField]
    private List<string> inner_translator;
    public List<string> InnerTranslator
    {
        get { return inner_translator; }
        set { inner_translator = value; }
    }

    private SortedList<string, string> country_list;

    public void OnDeserialization(object sender)
    {
        Debug.Assert(inner_translator == null);
        Count=country_list.Count;
    }
}
Was it helpful?

Solution

BinaryFormatter is, at the best of times, very brittle if you change things. Not least, there are huge problems with automatically implemented properties, obfuscaction, renaming, strong naming, etc.

As I recall, some of the rules about [OptionalField] changed just before it was released; the version tolerant thing didn't really work out as easily as had been planned, I expect.

My advice: if you want version tolerant serialization (i.e. you can serialize it today and deserialize it with the next version of your app), then don't use BinaryFormatter; this is (IMO) only suitable for passing data between the same version (remoting, AppDomains, etc).

For work between versions, I recommend contract-based serialization; things like XmlSerializer and DataContractSerializer (.NET 3.0), or for binary - protobuf-net or similar tools. All of these are much better at version tolerance (indeed, you don't even need to deserialize it into the same Type); plus they can be used between platforms - so you can serialize in .NET and deserialize in java/C++/etc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top