lambda表达式中对象的作用域

本文关键字:作用域 对象 表达式 lambda | 更新日期: 2023-09-27 18:18:08

我是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。只有在testMethod后面调用d1之后才会更改它。那么它是如何打印True ?我错过了什么?

lambda表达式中对象的作用域

d1d2都指向j的同一个实例。当你通过调用d1来设置j时,你也改变了d2可以看到的变量的值。

如果你想让它们有不同的j实例,你需要定义变量的作用域:

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

然而,如果你要这样做,那么你不妨有两个不同的变量,而不是说j1j2

当您创建委托时,它使用的范围之外的任何变量都将被捕获。在这种情况下,分配给d1d2的委托都捕获了在testMethod()中声明的变量j;它们不创建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);
}