以下の質問で、WaitCallBackとオブジェクトの代わりにデリゲートを渡す、タイプセーフな方法でQueueUserWorkItemを呼び出すためのこの巧妙なトリックを見つけました。ただし、期待どおりには機能しません。
リターンタイプを必要とせずに非同期アクティビティを実行するためのQueueUserWorkItem()とBeginInvoke()の違いは何ですか
問題を示すサンプルコードと出力を次に示します。
for (int i = 0; i < 10; ++i)
{
// doesn't work - somehow DoWork is invoked with i=10 each time!!!
ThreadPool.QueueUserWorkItem(delegate { DoWork("closure", i); });
// not type safe, but it works
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), Tuple.Create(" WCB", i));
}
void DoWork(string s, int i)
{
Console.WriteLine("{0} - i:{1}", s, i);
}
void DoWork(object state)
{
var t = (Tuple<string, int>)state;
DoWork(t.Item1, t.Item2);
}
そしてここに出力があります:
closure - i:10
WCB - i:0
closure - i:10
WCB - i:2
WCB - i:3
closure - i:10
WCB - i:4
closure - i:10
WCB - i:5
closure - i:10
WCB - i:6
closure - i:10
WCB - i:7
closure - i:10
WCB - i:8
closure - i:10
WCB - i:9
WCB - i:1
closure - i:10
クロージャーを使用してQueueUserWorkitemを呼び出す場合は、i = 10を呼び出しますが、WaitCallBackを使用する場合は、正しい値0〜9を取得することに注意してください。
だから私の質問は:
- クロージャ/デリゲートの方法を使用すると、iの正しい値が渡されないのはなぜですか?
- いったいどうやって10歳になるの?ループでは、0〜9の値しかありませんでしたか?