21

シナリオ:ループ内の非同期タスクは、プログラムの続行に伴って変化する引数を含むメソッドを実行します。

while(this._variable < 100)
{
    this._variable++; 
    var aTask = Task.Factory.StartNew(() =>
    {
        aList.add(this._variable);
        update(this._savePoint);
    });
}

タスクが完了するよりもループが速く実行される場合、リストは変数の現在の値を追加しますか、それとも変数はローカルに保存され、元の値が追加されますか?

4

1 に答える 1

20

クロージャは、値ではなく変数を閉じます。したがって、インクリメントすると、それを参照するタスクの動作が変わる_variable 可能性があります。

ローカルコピーを作成することで、これを防ぐことができます。

while (this._variable < 100)
{
    this._variable++;
    int local = _variable;
    var aTask = Task.Factory.StartNew(() =>
    {
        aList.add(local);
        update(this._savePoint);
    });
} 

または、値を状態としてタスクに渡すことができます。

while (this._variable < 100)
{
    this._variable++;
    var aTask = Task.Factory.StartNew(object state =>
    {
        aList.add((int)state);
        update(this._savePoint);
    }, this._variable);
} 

_variableこれらは両方とも、の値を新しい一時変数にコピーすることによって機能します。最初のケースでは、local変数はループのスコープ内で定義されているため、反復ごとに新しい変数を取得します。2番目のケースでは、引数_variableとしてタスクに渡すときの値のコピーを作成します。state参照型の場合_variable、これらのソリューションは機能しません。クローンを実行する必要があります。

于 2012-04-16T18:49:52.317 に答える