3

可能重复:
闭包中变量捕获的详细解释

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 中的代码如何使用 coef,而 coef 是构造函数的参数。如果您考虑一下,除非它获得 coef 的 ref 副本,否则它不应该起作用,因为一旦构造函数完成其工作,它的参数就会消失。但不知何故,调用 f 设法使用 coef 就好像它仍然存在一样。如何?

如果有人能解释这一点,我会很想得到一个很好的深入解释......

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

4

2 回答 2

2

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

闭包允许函数访问其直接词法范围之外的变量。一个上值是一个自由变量,它被一个闭包绑定(封闭)。据说关闭会“关闭”其升值。引用环境在创建闭包时将非本地名称绑定到范围内的相应变量,另外将它们的生命周期延长到至少与闭包本身的生命周期一样长。当稍后进入闭包时,可能来自不同的范围,函数将使用其非局部变量来执行,这些变量引用闭包捕获的变量。

关于你的第二个问题:使闭包静态会与功能原则的目的相矛盾。

于 2012-07-14T14:45:52.033 回答
2

Lambda 和其他委托被实现为闭包,由编译器创建的特殊对象,它将 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;
}
于 2012-07-14T14:46:21.107 回答