.net - C#,闭包和 lambda

  显示原文与译文双语对照的内容
0 0

我不打算问什么是闭包。 这是一个闭包:

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);
}

因为闭包关闭了变量,所以如果我们尝试调用"添加"列表的所有函数,结果将是 10. 这让我想起来,如果这是闭包,那么下面的示例也应该是一个闭包。

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

这里我们要关闭变量,所以变量的状态应该是变量的最后一个值,但它不是。 当我们改变x的值时,一个新的变量将创建一个新的变量来存储值。

时间:原作者:5个回答

0 0

区别在于第一个示例为每个委托共享相同的i 实例,因为 i 是为整个循环捕获的一次。 第二个示例对每个函数具有唯一值 1.5.

为了使第一个示例相同,可以在循环中使用本地变量,现在为每个函数单独捕获x 。

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

额外信息

下面是 Eric Lippert在主题上发表的两篇文章

在循环变量上关闭会考虑有害的第 1部分。

在循环变量上关闭会考虑有害的第 2部分。

原作者:
0 0

在第二个示例中,每次调用 add.Add 时都会改变x 。

除这里之外,你还可以将. NET 中的闭包视为一个类对象,该对象捕获上下文中的所有"外部"数据。 在第一个示例中,可以考虑创建带有一个方法( 那就是 i*2 )的类和一个引用对象"i"的字段。

原作者:
0 0

在第二个示例中,仍然有一个闭包正在创建,捕获变量x 。 变量x 是每个调用的一个新变量。 一个演示可能是为了。

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);
 }
}

但是,在第一个示例中,我是前面定义的,每次调用都。

原作者:
...