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实例上的代码都是相同的,但是每个实例都会获得相同代码的另一个副本吗?如果是这样,有没有办法让我的课程只运行该代码的一个副本? (比如让它以某种方式静止)
答案 0 :(得分:2)
该函数是一个所谓的闭包,在this wikipedia article
中有详细说明闭包允许函数访问其直接词法范围之外的变量。 upvalue是一个自由变量,它已被一个闭包绑定(关闭)。关闭据说“关闭”其上涨价值。引用环境在创建闭包时将非局部名称绑定到范围内的相应变量,另外将其生命周期延长至至少与闭包本身的生命周期一样长。当稍后输入闭包时,可能来自不同的范围,执行该函数时,其非局部变量引用闭包捕获的那些变量。
关于你的第二个问题:使闭包静止有点与功能原则的目的相矛盾。
答案 1 :(得分:2)
Lambdas和其他委托实现为closures,由编译器创建的特殊对象将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;
}