25

これは明らかにベストプラクティスではないようです。なぜそれがベストプラクティスではないのか、またはこれがどのように機能するのかを誰かが説明できますか? 説明を提供する本や記事をいただければ幸いです。

//The constructor
public Page_Index() {

    //create a local value
    string currentValue = "This is the FIRST value";

    //use the local variable in a delegate that fires later
    this.Load += delegate(object sender, EventArgs e) {
        Response.Write(currentValue);
    };

    //change it again
    currentValue = "This is the MODIFIED value";

}

出力される値は、2 番目の値"Modified"です。コンパイラの魔法のどの部分がこれを機能させていますか? これは、ヒープ上の値を追跡し、後で再度取得するのと同じくらい簡単ですか?

[編集]: いくつかのコメントを考慮して、元の文をいくつか変更します...

4

3 に答える 3

30

currentValue はローカル変数ではなくなりました。キャプチャされた変数です。これは次のようにコンパイルされます。

class Foo {
  public string currentValue; // yes, it is a field

  public void SomeMethod(object sender, EventArgs e) {
    Response.Write(currentValue);
  }
}
...
public Page_Index() {
  Foo foo = new Foo();
  foo.currentValue = "This is the FIRST value";
  this.Load += foo.SomeMethod;

  foo.currentValue = "This is the MODIFIED value";
}

Jon Skeet はC# in Depthでこれについて非常に優れた記事を書いています

変数 currentValue は現在、スタックではなくヒープ上にあることに注意してください。これには多くの意味があります。特に、さまざまな呼び出し元が使用できるようになったことは重要です。

これは Java とは異なります。Java では、変数のがキャプチャされます。C# では、変数自体がキャプチャされます。

于 2008-09-29T13:42:57.247 に答える
2

私が尋ねている質問は、それがローカル変数でどのように機能するかということだと思います[MG編集:「Ack - これを無視してください...」が後で追加されました]

そこが肝心だ; それは実際にはもはやローカル変数ではありません- 少なくとも、私たちが通常それらをどのように考えるか (スタック上など) に関してはそうではありません。1つのように見えますが、そうではありません。

そして、情報として、「良い習慣ではない」-匿名メソッドとキャプチャされた変数は、特にイベントを操作する場合、実際には非常に強力なツールです。それらを自由に使用してください。ただし、このルートをたどる場合は、Jon の本を手に取って、実際に何が起こっているのかを確実に理解することをお勧めします。

于 2008-09-29T13:52:24.760 に答える
0

クロージャー/デリゲート内の変数の値をキャプチャする必要があります。そうしないと、見たように変更できます。

デリゲートのローカル (内部) 変数に currentValue を割り当てます。

于 2008-09-29T13:45:08.660 に答える