C# 5.0 Breaking Changes

In the Language Lab section of the November 2012 issue of Visual Studio Magazine Patrick Steele highlights some of the lesser known changes to C#. Among the changes are some new attributes to help obtain caller information without having to resort to directly accessing StackFrames but that’s not what I want to call attention to. The more important part of his article are some breaking changes that anyone moving to C# 5 should be aware of.

The first of the breaking changes relate to capturing the value of an iteration variable in a lambda expression. If you’ve ever written a loop where the body contained a lambda expression that directly used the iteration variable you’ve encountered some unexpected behavior.  Consider Patrick’s example:

var computes = new List<Func<int>>();

foreach(var i in Enumerable.Range(0, 10))
{
	computes.Add(() => i * 2);
}

foreach(var func in computes)
{
	Console.WriteLine(func());
}

Without knowing the old behavior one could reasonably assume that the second loop would print out 0 – 18 (by 2s of course) but that’s not what happens. Prior to C# 5.0 deferring execution of the lambda expression to the second loop causes the expression to use the last value of i (9) so the number 18 is printed 10 times. We can observe similar behavior in LINQ as it iterates over sequences. The way to work around it was to create a state variable and capture it in a closure like in this modified example:

var computes = new List<Func<int>>();

foreach(var i in Enumerable.Range(0, 10))
{
	var state = i;
	computes.Add(() => state * 2);
}

foreach(var func in computes)
{
	Console.WriteLine(func());
}

Under C# 5.0 using a state variable is no longer necessary. The compiler will handle capturing the value of the iteration variable when it’s created.

The other breaking change relates to how named and positional arguments are handled. I typically only use explicit, ordered parameters so the old behavior never really affected me but previous versions of the compiler would evaluate named arguments before evaluating the ordered parameters. This behavior wasn’t particularly intuitive so it has been changed in C# 5.0. The only time this would really be a problem is when the expression being evaluated affected subsequent expression evaluations but since the change does affect compiler behavior it’s important to be aware of.

Advertisements