2011-12-16 93 views
2

我是C#的新手,並試圖瞭解lambda表達式以及代表。這是我運行的代碼:lambda表達式中的對象範圍

delegate bool D1(); 
delegate bool D2(int i); 

namespace Console 
{ 
    class Program 
    { 
     D1 d1; 
     D2 d2; 

     public void testMethod(int input) 
     { 
      int j = 0; 
      d1 =() => { j = 10; return j < input; }; 
      d2 = (x) => { return x == j; }; 
      System.Console.WriteLine("j = {0}", j); 

      bool res = d1(); 
      System.Console.WriteLine("res={0}, j ={1}", res, j); 

     } 

     static void Main(string[] args) 
     { 
      Program p = new Program(); 
      p.testMethod(10); 
      System.Console.WriteLine(p.d2(10)); 
      System.Console.ReadKey(); 
     } 
    } 
} 

什麼我不明白的是d2打印true調用。當構造d2時,j的值爲0。只有在testMethod後面調用d1後才發生更改。那麼如何印刷True?我在這裏錯過了什麼?

回答

6

d1d2都指代j的相同實例。當您通過調用d1來設置j時,您還在更改d2可以看到的變量的值。

如果你希望他們做的有j不同情況下你需要範圍的變量:

{ 
    int j = 0; 
    d1 =() => { j = 10; return j < input; }; 
} 

{ 
    int j = 0; 
    d2 = (x) => { return x == j; }; 
} 

但是,如果你要做到這一點,那麼你可能也有兩個不同的變量,代替j1j2。這將更具可讀性。

+0

謝謝..有什麼辦法可以控制這個,以便`d1`&`d2`將單獨的`j`實例? – Naveen 2011-12-16 12:34:55

3

當您創建一個委託時,捕獲了它使用的範圍之外的任何變量。在這種情況下,分配到d1d2的代表都捕獲testMethod()內聲明的變量j;他們不創建j的副本,他們捕獲實際變量。從這個意義上說,在d1d2,的生命週期中,它們的行爲就好像它是一個全局變量(儘管當然在C#中沒有這樣的東西像全局變量)。

如果您希望這些方法獲得單獨的j實例,則需要爲每種方法提供j的副本,而不是僅使用它。例如:

public void testMethod(int input) 
{ 
    int j = 0; 
    int k = j; 
    d1 =() => { j = 10; return j < input; }; 
    d2 = (x) => { return x == k; }; 
    System.Console.WriteLine("j = {0}", j); 

    bool res = d1(); 
    System.Console.WriteLine("res={0}, j ={1}", res, j); 

}