2009-12-30 47 views
7
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. 我可以確認複印沒有發生嗎?在C++中,我會實現複製構造函數並從裏面打印。

該標準的引用將不勝感激。任何相關的在線文章也是如此。將值類型捕獲到lambda時是否執行了複製?

回答

7

將不會有副本。 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」變量時會執行副本。即使沒有任何lambda表達式的局部變量,它也會這樣做。

6

它不會被複制,它會創建一個閉包。基本上它會將結構封裝在一個對象中,而不是在堆棧上創建它。

如果您想確保始終可以使用反射器,但沒有必要,則可以在Raymond Chen blog上解釋該行爲。

+0

唯一的問題是你不能爲一個結構創建一個無參數的構造函數。 – Rory 2009-12-30 20:13:49

+0

哎呀,我們對此深感抱歉 – albertein 2009-12-30 20:14:46

0

不,它不會複製,出於同樣的原因(編譯器創建一個場景類背後持有的值),當你捕捉一個lambda變量未創建的其他值類型的副本。

例如,如果你這樣做:

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

拉姆達共享「我」與申報範圍。你的結構也會發生同樣的情況。您可以將其作爲測試來證明不會發生複製。

3

請參閱The implementation of anonymous methods in C# and its consequences (part 1)。你的代碼實際上是這樣的:

class SomeHiddenClass { 
    SomeStruct someStruct; 
    someHiddenMethod() { 
     Console.WriteLine(someStruct.Num); 
    } 
    } 

    SomeHiddenClass someHiddenVar = new SomeHiddenClass(); 
    someHiddenVar.someStruct.Num = 5; 
    action = someHiddenVar.someHiddenMethod; 
+0

哎呀,嘿嘿。 +1 btw。 – Will 2009-12-30 20:16:01

相關問題