How to avoid captured variables?

I have a problem with

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

When DoSomething is executed, it gets the last value for each captured variable instead of the desired value. I can imagine a solution for this, but he imagines that you guys can come up with better solutions.

+6
source share
4 answers

The canonical way to solve this is to copy the values ​​into temporary variables that are declared inside the loop.

 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); } } 
+13
source

Refactor it:

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

It is simple and easy to understand. It states the intention of the developer, without cluttering the code with additional variables (as in the default case to solve this problem).

+4
source

For reference, I assume the following solution to my problem:

 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); } } 
+1
source

I would write it all like this, which avoids the problem and leaves absolutely no question about what is going on:

 var callbacks = words.SelectMany(w => categories.Select(c => new WaitCallback(state => { DoSomething(w, c); }) )); foreach (var callback in callbacks) ThreadPool.QueueUserWorkItem(callback); 
+1
source

Source: https://habr.com/ru/post/886241/


All Articles