我不打算问什么是关闭。这是一个关闭: 例如:
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);
}
由于闭包关闭变量,如果我们尝试调用“add”列表的所有Func,毫无疑问结果将是10。这让我想到,如果这是闭包,那么下面的例子也应该是一个闭包。
//Indirect way of writing the same example
Enumerable.Range(1, 5).ToList().ForEach(x => add.Add(() => x * 2));
这里我们也在关闭变量,因此变量的状态应该是变量的最后一个值,但事实证明,事实并非如此。这不是关闭。 lambda是否以不可变的方式构造其变量,即只要我们更改x的值,就会创建一个新变量来存储值?
答案 0 :(得分:1)
不同之处在于,第一个示例是为每个委托共享同一个i
实例,因为i
在整个循环中被捕获一次。第二个示例为每个函数提供1..5的唯一值。
要使第一个示例工作相同,您可以在循环中使用局部变量,如下所示,现在为每个函数单独捕获x。
foreach (int i in coll)
{
int x = i;
add.Add(() => x * 2);
}
<小时/> 添加信息
以下是Eric Lippert关于该主题的两篇文章
答案 1 :(得分:0)
在你的第二个例子中,每次调用add.Add时x都会改变 - 在你的第一个例子中,闭包中捕获了相同的变量“i”。
除此之外,您可以将.net中的闭包视为一个类对象,它捕获所有未在上下文中直接给出的“外部”数据。在您的第一个示例中,您可以考虑使用一个方法(用于执行i * 2)创建一个类,并考虑创建一个用于记住对象“i”的引用的字段。
答案 2 :(得分: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);
}
}
然而,在您的第一个示例中,我之前已定义,并且每次调用都会重复使用。