質問

次のコードを想定します:

foreach(Item i on ItemCollection)
{
   Something s = new Something();
   s.EventX += delegate { ProcessItem(i); };
   SomethingCollection.Add(s);
}

もちろん、すべてのデリゲートが同じItemを指しているため、これは間違っています。代替手段は次のとおりです。

foreach(Item i on ItemCollection)
{
   Item tmpItem = i;
   Something s = new Something();
   s.EventX += delegate { ProcessItem(tmpItem); };
   SomethingCollection.Add(s);
}

この場合、すべてのデリゲートは自分のアイテムを指します。

このアプローチはどうですか?他のより良い解決策はありますか?

役に立ちましたか?

解決

更新:この問題に関する広範な分析と解説がここにあります:

http: //ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/


これは非常に頻繁に報告される問題です。通常、これはコンパイラのバグとして報告されますが、実際には、コンパイラは仕様に従って正しいことをしています。無名関数は values ではなく、変数を閉じます。また、foreachループ変数は1つしかありません。したがって、各ラムダは同じ変数を閉じ、その変数の現在の値を取得します。

これはほとんどすべての人にとって驚くべきことであり、多くの混乱と多くのバグ報告につながります。将来の仮想バージョンの仕様と実装を変更して、ループ変数がループ構造内で論理的に宣言されるように検討し、" fresh"ループを通して毎回変数。

これは重大な変更になりますが、この奇妙な動作に依存している人の数は非常に少ないと思います。この件について意見がある場合は、上記のアップデートで言及したブログ投稿にコメントを追加してください。ありがとう!

他のヒント

コードの2番目のチャンクは、他のすべてのものを同じ状態に保つための最良のアプローチです。

ただし、 Item をとる Something にプロパティを作成することは可能です。次に、イベントコードは、イベントの送信者からこの Item にアクセスするか、イベントのeventargsに含まれる場合があります。したがって、閉鎖の必要がなくなります。

個人的に「不要な閉鎖の解消」を追加しました。それらを推論するのは難しい可能性があるため、価値のあるリファクタリングとして。

ItemCollectionが(generic)List の場合、使用できます ForEach -メソッド。 iごとに新しいスコープを提供します:

ItemCollection.ForEach(
    i =>
    {
        Something s = new Something();
        s.EventX += delegate { ProcessItem(i); };
        SomethingCollection.Add(s);
    });

または、他の適切な Linq -methodを使用できます- 選択

var somethings = ItemCollection.Select(
        i =>
        {
            Something s = new Something();
            s.EventX += delegate { ProcessItem(i); };
            return s;
        });
foreach(Something s in somethings)
    SomethingCollection.Add(s);

ここで直面している問題は、閉鎖などの言語構成に関連しています。 2番目のコードは問題を修正します。

foreach(Item i on ItemCollection)
{
   Something s = new Something(i);
   s.EventX += (sender, eventArgs) => { ProcessItem(eventArgs.Item);};
   SomethingCollection.Add(s);
}

「Something」クラスに「i」を渡して、EventXのイベント引数で使用するだけではありませんか

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top