揭开lambda工作原理之谜



可能重复:
关闭中变量捕获的详细说明

public class Polynom {
    public delegate double Func(double x);
    private Func f;
    public Polynom(params double[] coef) {
        f = (double x) => {
        double sum = 0;
        for ( int i = 0 ; i < coef.Length ; i++ )
            sum += coef[i] * Math.Pow(x,coef.Length-1-i);
        return sum;
        };
    }
    public double evaluate(double x) {
        return f(x);
    }
    public static void Main() {
        Polynom a=new Polynom(1,1,1);
        Polynom b=new Polynom(2 , 2 , 0);
        Console.WriteLine(a.evaluate(2));
        Console.WriteLine(b.evaluate(2));
        Console.ReadKey();
    }
}

注意f中的代码是如何使用cove的,而cove是构造函数的参数。如果你仔细想想,除非它得到cove的ref副本,否则这不应该起作用,因为一旦构造函数完成了它的工作,它的参数就会消失。但不知何故,调用f成功地使用了cove,就好像它仍然存在一样。如何?

如果有人能解释这一点,我会喜欢一个很好的深入解释。。。

我想知道的另一件事是,每个Polynom实例的代码都是相同的,但每个实例都会得到相同代码的另一个副本吗?如果是这样的话,有没有办法让我的类只运行该代码的一个副本?(比如以某种方式使其静态)

Lambdas和其他委托被实现为闭包,这是由编译器创建的特殊对象,它将lambda的一个方法与lambda完成执行所需的所有数据相结合。lambda内部使用的所有局部变量和参数的值都被隐式捕获为闭包的数据成员,因此它们在lambda本身不再被引用之前一直可用。

您可以将闭包看作是专门为lambda创建的一个特殊的匿名类。在您的情况下,闭包可能如下所示:

private Polynom_Closure {
    private readonly double[] coef;
    public Polynom_Closure(double[] coef) {
        this.coef = coef;
    }
    public double evaluate(double x) {
        double sum = 0;
        for ( int i = 0 ; i < coef.Length ; i++ )
            sum += coef[i] * Math.Pow(x,coef.Length-1-i);
        return sum;
    }
}

编译器使这个类对你来说是无形的,然后将它的用途插入到你的代码中:

public Polynom(params double[] coef) {
    f = new Polynom_Closure(coef).evaluate;
}

函数是一个所谓的闭包,在这篇维基百科文章中有很好的解释

闭包允许函数访问其直接词法范围之外的变量。upvalue是一个自由变量,它已与闭包绑定(闭合)。据说这次关闭"超过"了它的升值。在创建闭包时,引用环境将非局部名称绑定到范围中的相应变量,另外还将它们的生存期延长到至少与闭包本身的生存期一样长。当稍后输入闭包时,可能来自不同的范围,函数的非局部变量引用闭包捕获的变量来执行。

关于你的第二个问题:使闭包为静态会与函数原理的目的有些矛盾。

最新更新