7

問題が発生しています

foreach(var category in categories)
{
    foreach(var word in words)
    {
        var waitCallback = new WaitCallback(state =>
        {
            DoSomething(word, category);
        });

        ThreadPool.QueueUserWorkItem(waitCallback);
    }
}

が実行されると、DoSomething必要な値ではなく、キャプチャされた各変数の最新の値を受け取ります。私はこれに対する解決策を想像することができます、しかしそれはあなたたちがより良い解決策を思い付くことができると想像します

4

4 に答える 4

14

これを解決する標準的な方法は、ループで宣言されている一時変数に値をコピーすることです。

foreach(var category in categories)
{
    var catCopy = category;
    foreach(var word in words)
    {
        var wordCopy = word;
        var waitCallback = new WaitCallback(state =>
        {
            DoSomething(wordCopy, catCopy);
        });

        ThreadPool.QueueUserWorkItem(waitCallback);
    }
}
于 2011-04-19T13:34:57.193 に答える
4

次のようにリファクタリングします。

foreach(var category in categories) {
  foreach(var word in words) {
    DoSomethingAsync(word, category);
  }
}

...

private void DoSomethingAsync(string word, string category) {
  var waitCallback = new WaitCallback(state => DoSomething(word, category));
  ThreadPool.QueueUserWorkItem(waitCallback);
}

これはシンプルで理解しやすいです。これは、 (この問題を解決するためのデフォルトの方法のように)余分な変数でコードを乱雑にすることなく開発者の意図を示しています。

于 2011-04-19T13:41:35.827 に答える
1

参考までに、次のことが私の問題を解決すると思います。

foreach(var category in categories)
{
    foreach(var word in words)
    {
        var waitCallback = new WaitCallback(state =>
        {
            var kv = (KeyValuePair<string, string>)state;
            DoSomething(kv.Key, kv.Value);
        });

        var state2 = new KeyValuePair<string, string>(word, category);
        ThreadPool.QueueUserWorkItem(waitCallback, state2);
    }
}
于 2011-04-19T13:36:14.243 に答える
1

私はこのようにすべてを書きます。これは問題を回避し、何が起こっているのかについてまったく疑問を残しません。

var callbacks = words.SelectMany(w => categories.Select(c =>
    new WaitCallback(state => {
        DoSomething(w, c);
    })
));

foreach (var callback in callbacks)
    ThreadPool.QueueUserWorkItem(callback);
于 2011-04-19T13:39:02.773 に答える