Josh Smith

Follow me down the rabbit hole of cutting edge technology.
Automatic Properties and the BinaryFormatter

When I first encountered the C# 3.0 feature known as 'automatic properties' I had two, almost simultaneous, thoughts: "Oh great!" and "Oh no!"  Here is an automatic property:

public int Bar { get; set; }

This property does not reference a field, but I assure you it compiles just fine. This is very convenient for when you want to quickly add a property to a type, but do not want to bother typing all of this:

private int _bar;
public int Bar
{
    get { return _bar; }
    set { _bar = value; }
}

I was concerned about this great new language feature.  More than a few times in the past I have been burnt by the BinaryFormatter.  I would serialize an instance of a class, save it to disk, upgrade the DLL containing the class of the serialized object, and encounter an exception when deserializing that object during a subsequent run of the app.  If the type that has instances serialized was given a new field, had a field removed, or had a field renamed, the BinaryFormatter would throw an exception.  It demanded that the object being deserialized matched the type as which it was being instantiated. 

Here was my line of thinking...An automatic property uses a compiler-generated field as its backing store.  The name of that field is, practically speaking, random nonsense.  If I later decide to turn an automatic property into a normal property, with a corresponding field, I will have to change the name of that field.  The auto-generated field will disappear and my field will instead be used.  In that situation, wouldn't the BinaryFormatter throw an exception when deserializing an instance of the class, if it was serialized when the class still had an automatic property (with a compiler-generated field name)?  If so, that would be a subtle and nasty bug to track down!

I performed a test and discovered that this issue leaves us, the software debuggers of the world, in a bad situation.  It seems that BinaryFormatter has mellowed with age.  It does not throw exceptions any more when a field in the class is renamed or removed between object serialization and deserialization.  Instead, it just ignores the situation and moves on.  What this means is that, upon deserialization, the property that used to be "automatic" will no longer have its previous value.  Since its corresponding backing field was renamed, it is no longer set by BinaryFormatter.  To be honest, I would prefer that an exception was thrown in this situation just so that I knew right away that there was a problem. This is something to keep in mind when using and altering automatic properties in serializable types.

Here is the console app I created to test this:

#define AUTO

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace AutomaticPropertyTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Foo foo = null;

#if AUTO
            foo = new Foo();
            foo.Bar = 42;

            Console.WriteLine("Writing Foo with automatic property to file...");
            using (FileStream strm = new FileStream("asdf.dat", FileMode.Create))
                new BinaryFormatter().Serialize(strm, foo);
#else
            Console.WriteLine("Reading Foo with explicit backing field from file...");
            using (FileStream strm = new FileStream("asdf.dat", FileMode.Open))
                foo = new BinaryFormatter().Deserialize(strm) as Foo;
#endif

            Console.WriteLine("foo.Bar = " + foo.Bar);
            Console.ReadKey();
        }
    }

    [Serializable]
    class Foo
    {
#if AUTO
        public int Bar { get; set; }
#else
        private int _bar;
        public int Bar
        {
            get { return _bar; }
            set
            {
                if (value < 0)
                    throw new ArgumentOutOfRangeException("value");

                _bar = value;
            }
        }
#endif
    }
}

 
First run the app with the AUTO token defined.  That will save an instance of the Foo class to disk, with an automatic property called Bar.  Then comment out the AUTO token definition and run again.  This replaces the Bar property with a "normal" property and field, and deserializes the Foo object from disk.  The result is that Bar, which was previously set to 42, will return 0.  In a real debugging scenario, this could be a nightmare to track down, especially if you were not aware of this subtle side-effect of altering automatic properties. 

I think a good rule of thumb is: do not use automatic properties in serializable types.

Posted: 04 Feb 2008, 19:53
Filed under:

Comments

Karl Shifflett said:

Josh,

Nice discovery, I'm sure it will save developers from this situation.

This kind of feature in a production business application scares me anyway.  Another way to write code that is hard to maintain over time.  

I understand why we need the feature, but I'm not too sure I want to deploy code with it, especially since you discovered this potential side effect.

You know me, very cautious...

Cheers,

Karl

# February 4, 2008 8:47 PM

Joshua Smith said:

Karl,

I can see your point.  I wouldn't rule out automatic properties in all scenarios, though, just because they can cause trouble in certain situations.  If you do not use them in a serializable class, this issue will never arise.  Automatic properties are suitable for production code, if used judiciously.

Thanks,

Josh

# February 4, 2008 8:59 PM

J. Ambrose Little said:

Alternatively, the rule of thumb might be, don't use BinaryFormatter to serialize types, especially for any kind of long-term persistence where the structure of your type may change. :)

# February 4, 2008 10:03 PM

Joshua Smith said:

Ambrose,

In general, I agree.  However that is not always an option.  The consumer of a serializable type is not necessarily the creator of that type.  Also, if a .NET app is being ported to v3.5, switching to the SOAP formatter might not be an option.

Thanks,

Josh

# February 4, 2008 10:55 PM

Neil Mosafi said:

Hey Josh, great little investigation there!

Maybe I'm just old fashioned but I have to say I completely agree with Karl.  Most of these new C# features are fairly superflous and just a way to try and save people time.  Most of them seem to make code harder to maintain and make it easier for less experienced members of a dev team to make a mistake.  I honestly don't see what's so difficult about writing a field and a property accessor, especially when the IDE can automatically insert properties into your code for any fields you create!

Automatic properties are very implicit and it becomes much less obvious what actual *data* is contained within an instance of a class.  This problem you discovered will not manifest itself until a system actually goes into product and new versions are required to be deployed, and by then it may be too late to do anything about it and you will up with a major data migration headache.

You say the rule of thumb is not to use automatic properties on serializable classes.  This is all well and good but I actually think nowadays such classes are the only candidates for using automatic properties.  What I mean is that if you are writing any kind of UI component (e.g Asp.net control or WPF control) you will either be using ViewState or a Dependency Property as a backing store.  If you want to implement property changed notifications, you cannot use automatic properties too.

So this only really leaves business objects and DTO type classes (objects which need to be passed between tiers).  I would argue that those classes should normally be made serializable by default.  So what is the actual use for this C# feature?

Cheers

Neil

# February 5, 2008 7:37 AM

Sam Jack said:

Does anybody else detect the presence of an FxCop rule in the wings?!

# February 5, 2008 8:36 AM

Joshua Smith said:

Neil,

You raise some good points.  For the most part, I agree with Karl and you.  However, I can think of several places that automatic properties would be useful.  Internal helper classes, mock object classes, debugging-assistance classes, and generally any class that is not serialized or "integrated" with a platform (i.e. not classes that need DependencyProperties, etc.).  

Sam,

I think you're on to something... :)

Thanks,

Josh  

# February 5, 2008 9:26 AM

Andrew Smith said:

Using BinaryFormatter is ok but if you're going to use automatic properties then you should implement ISerializable and control what gets serialized and under what name.

# February 5, 2008 10:01 AM

Joshua Smith said:

Andrew,

Great point.  However, now we have entered into a strange realm of writing automatic properties to shave off some dev time/effort, and then implementing custom object serialization to ensure it works properly.  I guess you just can't have your cake and eat it too! :)

Thanks,

Josh

# February 5, 2008 10:09 AM

César F. Qüeb Montejo said:

I prefer to use the old method. Implementing the ISerializable interface and to use the OptionalField attribute, saves the omission of a property in a class, avoing of this way the exception when the object becomes deserialized.

I have tested this mechanism and work fine.

Regards

César

# February 6, 2008 10:07 AM

C&#195;&#169;sar F. Q&#195;&#188;eb Montejo said:

You can create readonly properties using the private command before the set accessor:

public int CustID

{

 get;

 private set;

}

Please visit http://blogs.msdn.com/wriju/archive/2007/03/27/c-3-0-features-automatic-property-part-3.aspx

regards

# February 7, 2008 12:28 PM

Scott said:

I totally agree with your concerns Josh.

# July 20, 2008 12:10 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS