开发者

C#, Closures and Lambdas

I am not going to ask the question what is closure. This is a closure: eg:

List<Func<int>> add = new List<Func<int>>();

List<int> coll = new List<int>(){1,2,3,4,5};
foreach (int i in coll)
{
     add.Add(() => i*2);
}

Since the closures closes over variables, no doubt the result开发者_如何学Go would be 10 for all cases if we try to Invoke all the Func of "add" list. This made me thinking, if this is closure, then the following example should also be a closure.

//Indirect way of writing the same example
Enumerable.Range(1, 5).ToList().ForEach(x => add.Add(() => x * 2));

Here also we are closing over variable, so state of the variable should be the last value of the variable but turns out, it is not. It's not closure. Does lambda constructs its variable in immutable way i.e as soon as we change the value of x, a new variable is created to store the value ?


The difference is that the first example is sharing the same instance of i for each delegate, since i was captured once for the entire loop. The second example you have unique values from 1..5 for each function.

To make the first example work the same, you can use a local variable in the loop as follows, now x is captured separately for each function.

  foreach (int i in coll)
  {
    int x = i;
    add.Add(() => x * 2);
  }


Addtional Info

Here is a two part post on the topic by Eric Lippert

Closing over the loop variable considered harmful - Part 1

Closing over the loop variable considered harmful - Part 2


in your second example the x will change every time add.Add is called - in your first example the same variable "i" is caught in the closure.

Aside from this you can think of a closure in .net just as a class-object that captures all "external" data not directly given in the context. In your first example you can think of creating a class with one Method (that does the i*2) and one field where a reference to your object "i" is remembered.


In your second example there still is a closure being created, capturing the variable x. The variable x is a new variable for every invocation though. A demonstration is perhaps in order.

class SomeClass
{
    List<int> col = new List<int> {1,2,3,4,5};

    void SomeFunction()
    {
        for (int x = 0; x < 6; x++)
            ForEachFunction(x);
    }

    void ForEachFunction(int x) 
    {
        // x here is a copy of the variable from the for loop
        col.Add(x);
    }
}

In your first example however, i was defined earlier, and was reused for each invocation.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜