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 がまだ存在しているかのように使用できます。どうやって?

誰かがこれを説明できるなら、私は良い深い説明が大好きです...

私が知りたいもう 1 つのことは、コードはすべての Polynom インスタンスで同じですが、すべてのインスタンスが同じコードの別のコピーを取得するということです。もしそうなら、そのコードのコピーを 1 つだけ使用してクラスを実行する方法はありますか? (どういうわけか静的にするように)

4

2 に答える 2

2

関数はいわゆるクロージャーであり、このウィキペディアの記事でよく説明されています

クロージャにより、関数は直接のレキシカル スコープ外の変数にアクセスできます。upvalue は、クロージャーでバインド (クローズオーバー) された自由変数です。クロージャーは、その上位値を「閉じる」と言われます。参照環境は、クロージャーが作成された時点で非ローカル名をスコープ内の対応する変数にバインドし、さらにそれらの有効期間を少なくともクロージャー自体の有効期間と同じくらいまで延長します。後で、おそらく別のスコープからクロージャに入ると、クロージャによってキャプチャされたものを参照する非ローカル変数を使用して関数が実行されます。

2 番目の質問について: クロージャを静的にすることは、機能原則の目的と多少矛盾します。

于 2012-07-14T14:45:52.033 に答える
2

ラムダおよびその他のデリゲートは、クロージャとして実装されます。これは、ラムダのメソッドと、ラムダが実行を完了するために必要なすべてのデータを組み合わせる、コンパイラによって作成される特別なオブジェクトです。ラムダ内で使用されるすべてのローカル変数とパラメーターの値は、クロージャーのデータ メンバーとして暗黙的にキャプチャされるため、ラムダ自体が参照されなくなるまで使用できます。

クロージャは、ラムダ専用に作成された特別な匿名クラスと考えることができます。あなたの場合、クロージャーは次のようになります。

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 に答える