Monday, September 1, 2008

Subtleties in C# Anonymous methods

Last Friday I had a really bad time figuring out a bug in an anonymous method. The bug was related with the way anonymous methods are implemented in C# and variable scoping. Being the scenes the compiler is generating a class to hold the delegate and references to the variables that are grabbed in the scope of the block holding the delegate. The reference will be hold in memory for the all lifecycle of the delegate object.

The original code was:

foreach (PropertyInfo property in allProperties)
{
    object propertyValue = GetTypePropertyValue(this, property);

    MyObject1 myObject1Value = propertyValue as INotifyPropertyChanged;
    if (myObject1Value != null)
    {
        myObject1Value.PropertyChanged += delegate(object sender, PropertyChangedEventArgs ev)
        {
            this.NotifyPropertyChanged(property.Name);
        };
    }
}
The code fixed code is something like this:
foreach (PropertyInfo property in allProperties)
{
    object propertyValue = GetTypePropertyValue(this, property);

    MyObject1 myObject1Value = propertyValue as INotifyPropertyChanged;
    if (myObject1Value != null)
    {
        string propertyName = property.Name;
        myObject1Value.PropertyChanged += delegate(object sender, PropertyChangedEventArgs ev)
        {
            this.NotifyPropertyChanged(propertyName);
        };
    }
}

The difference is declaring a string variable outside the anonymous method and copying the property’s name into it. Being the scene the compiler will grab a reference to the string that is an immutable object and that reference won’t get modified.

No comments: