Less known feature of C# 5.0 — modified closure behaviour

If you were asked to mention new features of C# 5.0, then you would probably say, first of all, async / await. However, on MSDN there is list of changes that could hardly be considered as well-known, even after almost 1 year after .NET 4.5 RTM was published. In this post I briefly explain one of them, that in my opinion is worth remembering.

As a C# developer, you are hopefully aware of the outer variable trap issue. Yet, in the version 5.0 of the language, the behaviour of a closure has been slightly altered. Let’s take a look at first (regarding comment “switches”) half of the following code:

 
class Program
{
  static void Main(string[] args)
  {
    //* 
    List<Action> lambdas = new List<Action>();
    foreach (var i in new int[] { 0, 1 })
    {
      lambdas.Add(() => { Console.WriteLine(i); });
    }

    lambdas[0]();
    lambdas[1]();

    /*/

    List<Action> lambdas = new List<Action>();
    for (int i = 0; i <= 1; i++)
    {
      lambdas.Add(() => { Console.WriteLine(i); });
    }

    lambdas[0]();
    lambdas[1]();    

  //*/
  }
}

Now let’s try to compile it using version 3.5 and 4.5 of the compiler. This assumes default installations, the file is named Program.cs and, of course, as 4.5 version of run-time is in-place update, it resides in the directory named after 4.0.

  1. c:\Windows\Microsoft.NET\Framework\v3.5\csc.exe Program.cs && Program
  2. c:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe Program.cs && Program

The former example results in 1 1 printed into the console and the latter results in 0 1 printed. The 1 1 result is caused by typical outer variable trap, where the lambdas are kind of bound to the captured variable itself (which in the end has a value of 1), but not to its value at the time of creation of the lambda. The breaking change introduced in version 5.0 of the language brings the behaviour to what actually might have been expected — capture the value indicated by the sequence of the code being executed. However, this works only inside foreach loop.

By switching the comments (deleting the first slash) you can prove standard for loop behaves exactly the same in both versions of compiler and results in printing 2 2 indicating outer variable trap.

One comment

  1. Less known feature of C# 5.0 — modified closure behaviour | PJSen Blog…

    Dziękujemy za dodanie artykułu – Trackback z dotnetomaniak.pl…

Leave a Reply

Your email address will not be published. Required fields are marked *

Protection against spam * Time limit is exhausted. Please reload CAPTCHA.