如何在.NET中实现匿名方法中的捕获值

我很好奇.NET实现及其背后的决定。

例如,在Java中,匿名类中使用的所有捕获值都必须是最终的。 这个要求似乎在.NET中被删除了。

此外,与参考类型相比,值类型的捕获值的实现是否存在差异?

谢谢

找出它是如何实现的最简单方法是尝试它。 编写一些使用捕获变量的代码,编译它,然后在Reflector中查看它。 请注意,它是捕获的变量 ,而不是 。 这是Java和C#在这个领域的重大差异之一。

基本思想是包含至少一个捕获变量的每个范围级别都会生成一个新类,其中包含已捕获变量的字段。 如果有多个级别,那么内部范围也有一个字段用于下一个范围输出,依此类推。 堆栈上的真正局部变量最终是对自动生成的类的实例的引用。

这是一个例子:

using System; using System.Collections.Generic; class Program { static void Main() { List actions = new List(); for (int i=0; i < 5; i++) { int copyOfI = i; for (int j=0; j < 5; j++) { int copyOfJ = j; actions.Add(delegate { Console.WriteLine("{0} {1}", copyOfI, copyOfJ); }); } } foreach (Action action in actions) { action(); } } } 

(如果你没有复制课程,你会得到不同的结果 - 实验!)这被编译成如下代码:

 using System; using System.Collections.Generic; class Program { static void Main() { List actions = new List(); for (int i=0; i < 5; i++) { OuterScope outer = new OuterScope(); outer.copyOfI = i; for (int j=0; j < 5; j++) { InnerScope inner = new InnerScope(); inner.outer = outer; inner.copyOfJ = j; actions.Add(inner.Action); } } foreach (Action action in actions) { action(); } } class OuterScope { public int copyOfI; } class InnerScope { public int copyOfJ; public OuterScope outer; public void Action() { Console.WriteLine("{0} {1}", outer.copyOfI, copyOfJ); } } } 

对捕获变量的每个引用最终都会通过生成的类的实例,因此它不仅仅是一次性副本。 (好吧,在这种情况下,代码中没有其他内容使用捕获的变量,但您可以轻松想象它可以。)请注意,对于外部循环的任何一次迭代,五个新实例都共享一个OuterScope实例。 您可能想尝试在委托中使用额外的代码来查看它如何影响事物 - 如果委托更改copyofI ,那么更改将在下一个委托中看到; 将无法看到对copyOfJ更改,因为下一个委托将使用InnerScope的单独实例。