C# Disciples

my life in Avalon ….

Closures in C# can be evil

I had a problem with yield and closures. A friend Glenn Block gave me a good link on this. you can read it here >> http://codebetter.com/blogs/matthew.podwysocki/archive/2008/09/12/side-effects-and-functional-programming.aspx

here is an abstract from the blog about the problem. This can cause a lot of pain and that is why I am sharing it so that you do not fall in the same trap!

Closures and Lazy Evaluation

One last topic for this post revolves around variable instantiation around closures and what it means to you in regards to lazy evaluation.  Let’s look at a quick example of some of the issues you might face. 

C#

var contents = new List<Func<int>>();
var s = new StringBuilder();
for (var i = 4; i < 7; i++)
    contents.Add(() => i);
for (var k = 0; k < contents.Count; k++)
    s.Append(contents[k]());
Console.WriteLine(s);

What we might expect the results to be in this case would be 456.  But that’s not the case at all here.  In fact, the answer you will get is 777.  Why is that?  Well, it has to do with the way that the C# compiler creates a helper class to enable this closure.  If you’re like me and have Resharper, you’ll notice that it gives a warning about this with "Access to modified closure".  If we change this to give ourselves a local variable inside the loop closure construct to initialize the value properly.  If we do that and change our code, it will now look like this:

C#

var contents = new List<Func<int>>();
var s = new StringBuilder();
for (var i = 4; i < 7; i++)
{
var j = i;
    contents.Add(() => j);
}
for (var k = 0; k < contents.Count; k++)
    s.Append(contents[k]());
Console.WriteLine(s);

Jason Olson has a pretty good explanation in his post "Lambdas – Know Your Closures".

 

Hope it helps!

June 2, 2010 Posted by | C# 3.0, tips and tricks | 8 Comments

   

Follow

Get every new post delivered to your Inbox.

Join 845 other followers