Click here to Skip to main content
15,891,184 members
Articles / Programming Languages / C#

C#: Trouble with Lambdas in For Loops

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
14 May 2010Apache1 min read 5.8K   1  
C#: Trouble with Lambdas in For Loops

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

C#
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:

C#
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. :)

This article was originally posted at http://www.ikriv.com/blog?p=491

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0


Written By
Technical Lead Thomson Reuters
United States United States
Ivan is a hands-on software architect/technical lead working for Thomson Reuters in the New York City area. At present I am mostly building complex multi-threaded WPF application for the financial sector, but I am also interested in cloud computing, web development, mobile development, etc.

Please visit my web site: www.ikriv.com.

Comments and Discussions

 
-- There are no messages in this forum --