如何避免捕获变量
本文关键字:变量 何避免 | 更新日期: 2023-09-27 17:51:23
我有一个问题
foreach(var category in categories)
{
foreach(var word in words)
{
var waitCallback = new WaitCallback(state =>
{
DoSomething(word, category);
});
ThreadPool.QueueUserWorkItem(waitCallback);
}
}
当执行DoSomething
时,它接收每个捕获变量的最新值,而不是我想要的值。我能想到一个解决办法,但我希望你们能想出更好的办法
解决这个问题的规范方法是将值复制到临时变量中,这些临时变量在循环中声明为。
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);
}
}
重构为:
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);
}
这很简单,容易理解。它陈述了开发人员的意图,而不会用额外的变量使代码混乱(就像解决这个问题的默认方式一样)。
作为参考,我认为以下内容可以解决我的问题:
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);
}
}
我将把整个代码写成这样,这样就避开了问题,并且对正在发生的事情没有任何疑问:
var callbacks = words.SelectMany(w => categories.Select(c =>
new WaitCallback(state => {
DoSomething(w, c);
})
));
foreach (var callback in callbacks)
ThreadPool.QueueUserWorkItem(callback);