0

この回答からhttps://stackoverflow.com/a/6457528/299110

ctrl と rule の値が毎回変化ctrl.PreRender += (sender, e) => ControlPreRender(ctrl, rule);する 内の 1 つ以上のコントロールを使用しています。foreach

ただし、ControlPreRenderメソッドが呼び出されると、ruleパラメーターは、イベント ハンドラーがアタッチされた送信者と一致していないように見えます。

私はここで何かが欠けていることを知っていますが、何がわからないのですか!

更新: 回答ありがとうございます。Eric Lippert のブログで実際に説明されています。反対票を投じた人が示唆したように、以下のコードをさらに追加して、問題を少し改善できることを願っています。

foreach (var ctrl in controls) 
{
    // ...
    foreach (var rule in rules)
    {
        // ...
        ctrl.PreRender += (sender, e) => ControlPreRender(ctrl, rule);
    }
}

public static void ControlPreRender(Control ctrl, ControlRule rule)
{
    // ...
}
4

2 に答える 2

3

一時変数が必要だと思います:

foreach(var rule in rules)
{
    var tmpRule = rule;
    ctrl.PreRender += (sender, e) => ControlPreRender(sender as Control, tmpRule);
}

その理由は次のとおりです。その一時変数がないと、すべての匿名メソッドが同じインスタンスを参照し、すべてのルールをループすると変化します。これは「変更されたクロージャへのアクセス」と呼ばれます。erikallen が言及しているように、これは C# 5 で修正されています。

自分で簡単に確認できます: ブレークポイントを設定ControlPreRenderし、最初のブレークポイント ヒットでルール パラメーターのオブジェクト ID を作成します。ブレークポイントの次のすべてのヒットで、ルール パラメーターが同じオブジェクト ID を持つことがわかります。これは、まったく同じインスタンスであることを意味します。

于 2012-09-13T12:02:36.080 に答える
1

Eric Lippert は、これに関する2 つの優れたブログ記事を投稿しました。.NET 4.5 では、foreach ループが期待どおりに動作するように、破壊的な変更が実際に加えられていることがわかります。(Eric は C# 5 に言及していますが、これは紛らわしいことに、.NET 4.5 で使用されるコンパイラ バージョンです。) Eric は次のように述べています。

「これは、私たちが受け取る最も一般的な誤ったバグ レポートの 1 つです。つまり、誰かがコンパイラにバグを発見したと考えていますが、実際にはコンパイラは正しいのです。」

エリックの投稿に従って、@ダニエルはすでに正しいコードを投稿していることに注意してください。

于 2012-09-13T12:08:59.430 に答える