C#、闭包和 Lambda 表达式
我不会问什么是封闭的问题。这是一个闭包: 例如:
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 的值,就会创建一个新变量来存储该值?
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 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 ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不同之处在于,第一个示例为每个委托共享相同的
i
实例,因为i
在整个循环中被捕获一次。第二个示例中,每个函数都有 1..5 之间的唯一值。为了使第一个示例同样工作,您可以在循环中使用局部变量,如下所示,现在为每个函数单独捕获 x。
Addtional Info
这是 Eric Lippert 撰写的关于该主题的两部分帖子
关闭被视为有害的循环变量 - 第 1 部分
结束被认为有害的循环变量 - 第 2 部分
The difference is that the first example is sharing the same instance of
i
for each delegate, sincei
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.
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
在你的第二个例子中,每次调用 add.Add 时 x 都会改变 - 在你的第一个例子中,相同的变量“i”被捕获在闭包中。
除此之外,您可以将 .net 中的闭包视为一个类对象,它捕获上下文中未直接给出的所有“外部”数据。在您的第一个示例中,您可以考虑创建一个具有一个方法(执行 i*2)和一个字段的类,其中会记住对对象“i”的引用。
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.
在第二个示例中,仍然创建了一个闭包,捕获变量 x。不过,变量 x 对于每次调用都是一个新变量。也许应该进行一次演示。
然而,在您的第一个示例中, i 是之前定义的,并且在每次调用中都被重用。
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.
In your first example however, i was defined earlier, and was reused for each invocation.