0

次のクラスがあります。

public class myType
{
  public event Action myAction;
}

そして、そのクラスのいくつかのインスタンスを含む辞書。

var myDictionary = new Dictionary<myType, string>();

私のメインには、署名がvoid SomeMethod(myType、Dictionary)のメソッドがあります。

次のループを使用して、オブジェクトの動作を追加します。

foreach(var pair in myDictionary)
  pair.Key.myAction += () => SomeMethod(pair.Key, myDictionary);

このループを実行した後、オブジェクトの1つのアクションが呼び出されると、ループがすべてのラムダ式のディクショナリの最後のpair.Keyを使用したかのようになります。

一方、ループに小さな変更があります。

foreach(var pair in myDictionary)
{
  myType temp = pair.Key;
  pair.Key.myAction += () => SomeMethod(temp, myDictionary);
}

このループを実行した後、すべてのオブジェクトアクションは期待どおりに機能します。

なぜそのような変更がそのような効果をもたらすのか、私は少し戸惑っています。キーと値のペアは構造体である可能性があり、キー自体は参照型(私のクラスのインスタンス)です。これがこのように動作する理由はありますか?

提案を事前に感謝します。

4

1 に答える 1

1

このループを実行した後、オブジェクトの1つのアクションが呼び出されると、ループがすべてのラムダ式のディクショナリの最後のpair.Keyを使用したかのようになります。

はい、まさにそれが起こっていることです。pairすべてのイベントハンドラーによって使用される単一の変数があります。ループの後、変数にはループの最後の項目のキーが含まれます。

スコープでローカル変数を作成し、それをラムダ式で使用することにより、実際には各イベントハンドラーのクロージャーを作成しています。ローカル変数は通常のローカル変数としてスタックに格納されませんが、クロージャーに格納されます。各イベントハンドラーには独自のクロージャーがあるため、イベントハンドラーごとに1つのバージョンのローカル変数を取得します。

(最初のコードにもクロージャがありますが、これは変数が現在のスコープを存続させるためだけのものであり、イベントハンドラーは同じクロージャを共有します。)

于 2013-03-03T23:31:03.993 に答える