Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

C#: Trouble with Lambdas in For Loops

0.00/5 (No votes)
14 May 2010 1  
C#: Trouble with Lambdas in For Loops

I had an interesting bug the other day. I wrote a foreach loop along these lines:

foreach (var entry in controlsByName)
{
    entry.Key.SomeEvent += (sender,args)=>{ProcessControlName(entry.Value);}
}

Looks innocent enough, right? There is a big catch here. In functional languages, we are accustomed to the fact that everything is immutable. I subconsciously transferred this notion to C# lambdas. I thought that the lambdas capture outer variables by value and carry this immutable value with them forever. This is wrong!.

C# language specification (found at C:\Program Files\Microsoft Visual Studio 9.0\VC#\Specifications if you have Visual Studio 2008) states in paragraph 7.14.4 that outer variables are captured by reference. They don’t use these exact words, but that’s the idea. If you change the value of the variable, all lambdas that captured it will be affected.

Even more surprisingly, there will be only one copy of the loop variable such as entry above, and all lambdas will share this single copy. This means that the code above has a bug. After the loop has finished, if SomeEvent is fired by one of the controls, the name passed to ProcessControlName() will always be the name of the last control, regardless of which control fired the event!

It turns out, you can even exploit this variable sharing making lambdas to communicate like this:

private void GetTangledLambdas(out Func<int> getter, out Action<int> setter)
{
    int x = 0;
    getter = () => x;
    setter = v => {x = v;};
}
 
[TestMethod]
public void Lambads_Can_Communicate_Through_Captured_Variable()
{
    Func<int> getter;
    Action<int> setter;
    GetTangledLambdas(out getter, out setter);
    setter(10);
    Assert.AreEqual(10, getter());
    setter(20);
    Assert.AreEqual(20, getter());
}

This, of course, is not even close to functional programming, even though it uses lambdas. :)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here