将值类型捕获到lambda中时是否执行复制?

struct SomeStruct { public int Num { get; set; } } class Program { static Action action; static void Foo() { SomeStruct someStruct = new SomeStruct { Num = 5 }; action = () => Console.WriteLine(someStruct.Num); } static void Main() { Foo(); action.Invoke(); } } 
  1. 是否创建了lambda时创建的someStruct的副本?
  2. Foo返回时是否创建了someStruct的副本?
  3. 我可以validation没有发生复制吗? 在C ++中,我实现了复制构造函数并从中进行打印。

该标准的引文将不胜感激。 任何相关的在线文章也是如此。

没有副本。 Lambdas捕获变量,而不是值。

您可以使用Reflector查看编译代码:编译器会将“someStruct”变量移动到辅助类中。

 private static void Foo() { DisplayClass locals = new DisplayClass(); locals.someStruct = new SomeStruct { Num = 5 }; action = new Action(locals.b__1); } private sealed class DisplayClass { // Fields public SomeStruct someStruct; // Methods public void b__1() { Console.WriteLine(this.someStruct.Num); } } 

复制结构永远不会导致用户定义的代码运行,因此您无法真正检查它。 实际上,代码将在分配给“someStruct”变量时进行复制。 即使对于没有任何lambdas的局部变量,它也会这样做。

它不会被复制,它会创建一个闭包。 基本上它会将结构封装在一个对象中,而不是在堆栈上创建它。

如果你想确定你总是可以使用reflection器,但没有必要,这个行为在Raymond Chen博客上有解释。

请参阅C#中匿名方法的实现及其后果(第1部分) 。 你的代码实际上是这样的:

  class SomeHiddenClass { SomeStruct someStruct; someHiddenMethod() { Console.WriteLine(someStruct.Num); } } SomeHiddenClass someHiddenVar = new SomeHiddenClass(); someHiddenVar.someStruct.Num = 5; action = someHiddenVar.someHiddenMethod; 

<开始自我推销>我刚才在博客上写了这篇文章。 http://crazorsharp.blogspot.com/2009/06/how-do-closures-captured-variables-work.html

不,它不会复制,出于同样的原因(编译器创建一个幕后类来保存值),当您在lambda中捕获变量时,不会创建其他值类型的副本。

例如,如果你这样做:

 int i = 7; Action a = () => Console.WriteLine("lambda i=" + i); i++; a(); //prints 8 Console.WriteLine("main i=" + i); //prints 8 

lambda与声明范围共享’i’。 你的结构也会发生同样的事情。 您可以将此作为测试来certificate不会发生复制。