代码之家  ›  专栏  ›  技术社区  ›  GilliVilla

外部变量陷阱

  •  46
  • GilliVilla  · 技术社区  · 15 年前

    外部变量陷阱究竟是什么?

    编辑:合并乔恩·斯凯特的命令:)

    Eric Lippert on the Outer Variable Trap

    5 回复  |  直到 4 年前
        1
  •  64
  •   funie200 gxyd    4 年前

    当开发人员期望lambda表达式或匿名委托捕获变量的值时,实际捕获变量本身时,就会出现“外部变量陷阱”。

    例子:

    var actions = new List<Action>();
    for (var i = 0; i < 10; i++)
    {
        actions.Add(() => Console.Write("{0} ", i));
    }
    foreach (var action in actions)
    {
        action();
    }
    

    0 1 2 3 4 5 6 7 8 9
    

    可能输出#2:

    10 10 10 10 10 10 10 10 10 10
    

    修正:

    var actions = new List<Action>();
    for (var i = 0; i < 10; i++)
    {
        var j = i;
        actions.Add(() => Console.Write("{0} ", j));
    }
    foreach (var action in actions)
    {
        action();
    }
    

    有关详细信息,请参见 Eric Lippert's blog

        2
  •  5
  •   heisenberg    15 年前

    像这样的

    foreach (var s in strings)
        var x = results.Where(r => (r.Text).Contains(s));
    

        3
  •  2
  •   Saeb Amini    8 年前

    值得注意的是,这个陷阱的存在 foreach 循环太多,但是 has been changed foreach公司 循环闭包现在每次都在循环变量的新副本上关闭。所以下面的代码是:

    var values = new List<int>() { 100, 110, 120 };
    var funcs = new List<Func<int>>();
    foreach (var v in values)
        funcs.Add(() => v);
    foreach (var f in funcs)
        Console.WriteLine(f());
    

    印刷品 120 120 120 <C#5.0级 ,但是 100 110 120 >

    然而 for

        4
  •  1
  •   TrueWill    15 年前

    var objects = new []
        {
            new { Name = "Bill", Id = 1 },
            new { Name = "Bob", Id = 5 },
            new { Name = "David", Id = 9 }
        };
    
    for (var i = 0; i < 10; i++)
    {
        var match = objects.SingleOrDefault(x => x.Id == i);
    
        if (match != null)
        {
            Console.WriteLine("i: {0}  match: {1}", i, match.Name);
        }
    }
    

    这将打印:

    i: 1  match: Bill
    i: 5  match: Bob
    i: 9  match: David

    ReSharper 将警告“访问修改的闭包”,在这种情况下可以安全地忽略它。

        5
  •  0
  •   Heather    15 年前

    http://en.wikipedia.org/wiki/Closure_(computer_science)

    此外,本文还提供了一个更为具体的C#实现:

    http://blogs.msdn.com/b/abhinaba/archive/2005/08/08/448939.aspx

    总之,tl;lr是变量作用域在匿名委托或lambda表达式中与在代码中的其他任何地方一样重要——行为只是没有那么明显。