How do I get around this lambda expression outer variable issue?

后端 未结 4 1790
感情败类
感情败类 2021-01-19 18:47

I\'m playing with PropertyDescriptor and ICustomTypeDescriptor (still) trying to bind a WPF DataGrid to an object, for which the data is stored in a Dictionary.

Sinc

相关标签:
4条回答
  • 2021-01-19 19:10

    For some additional thoughts on this issue see

    http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/

    0 讨论(0)
  • 2021-01-19 19:15

    create a local copy of s inside your for loop and use that.

    for(string s in this.Keys) {
    string key = s;
    //...
    }
    
    0 讨论(0)
  • 2021-01-19 19:25

    Simply:

            foreach (string s in this.Keys)
            {
                string copy = s;
                var descriptor = new PersonPropertyDescriptor(
                        copy,
                        new Func<object>(() => { return this[copy]; }),
                        new Action<object>(o => { this[copy] = o; }));
                propList.Add(descriptor);
            }
    

    With captured variables, it is where it is declared that is important. So by declaring the captured variable inside the loop, you get a different instance of the capture-class per iteration (the loop variable, s, is technically declared outside the loop).

    0 讨论(0)
  • 2021-01-19 19:27

    Marc's solution is of course correct, but I thought I'd expand upon WHY below. As most of us know, if you declare a variable in a for or foreach statement, it only lives as long as what's inside, which makes it seem like the variable is the same as a variable declared in the statement-block of such a statement, but that's not right.

    To understand it better, take the following for-loop. Then I'll re-state the "equivalent" loop in a while-form.

    for(int i = 0; i < list.Length; i++)
    {
        string val;
        list[i] = list[i]++;
        val = list[i].ToString();
        Console.WriteLine(val);
    }
    

    This works out to in while-form like below: (it isn't exactly the same, because continue will act differently, but for scoping rules, it's the same)

    {
        int i = 0;
        while(i < list.Length)
        {
            {
                string val;
                list[i] = list[i]++;
                val = list[i].ToString();
                Console.WriteLine(val);
            }
            i++;
        }
    }
    

    When "exploded" out this way, the scope of the variables becomes clearer, and you can see why it always captures the same "s" value in your program, and why Marc's solution shows where to place your variable so that a unique one is captured every time.

    0 讨论(0)
提交回复
热议问题