Как избежать захваченных переменных? - PullRequest
6 голосов
/ 19 апреля 2011

У меня проблема с

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

        ThreadPool.QueueUserWorkItem(waitCallback);
    }
}

Когда выполняется DoSomething, он получает самое последнее значение для каждой захваченной переменной вместо значения, которое я желал. Я могу вообразить решение для этого, но представьте, что вы, ребята, можете придумать лучшие решения

Ответы [ 4 ]

13 голосов
/ 19 апреля 2011

Канонический способ решить это - скопировать значения во временные переменные, которые объявлены внутри цикла.

4 голосов
/ 19 апреля 2011

Refactor это до:

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);
}

Это просто и легко понять. В нем говорится о намерении разработчика без загромождения кода дополнительными переменными (как по умолчанию для решения этой проблемы).

1 голос
/ 19 апреля 2011

Я бы написал все это так, что это уклоняется от проблемы и не оставляет абсолютно никаких вопросов о том, что происходит:

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

foreach (var callback in callbacks)
    ThreadPool.QueueUserWorkItem(callback);
1 голос
/ 19 апреля 2011

Для справки, я думаю, что следующее решило бы мою проблему:

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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...