lambda表达式中对象的范围

时间:2011-12-16 12:25:35

标签: c# delegates lambda

我是C#的新手并尝试了解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。它仅在d1稍后调用testMethod后才更改。那么如何打印True?我在这里错过了什么?

2 个答案:

答案 0 :(得分:6)

d1d2都引用j的同一个实例。当您通过调用j设置d1时,您也会改变d2可以看到的变量的值。

如果你想要它们有j的不同实例,你需要对变量进行范围调整:

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

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

但是,如果您要这样做,那么您可能会有两个不同的变量,比如j1j2。这将更具可读性。

答案 1 :(得分:3)

创建委托时,会捕获其使用范围之外的任何变量。在这种情况下,分配给d1d2的代理都会捕获j内声明的变量testMethod();他们不创建j的副本,他们捕获实际变量。从这个意义上说,在d1d2的生命周期中,j在它们内部表现就好像它是一个全局变量(尽管在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);

}