2011-12-16 60 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); 

}