1

以下の値 X が、値 i ではなく常に値 "int.Parse(radTextBoxFloodRequests.Text)" になるのはなぜですか?

C# コード

private void radButtonTaskWithStatus_Click(object sender, EventArgs e)
{
    try
    {
        Task<int>[] tasks = new Task<int>[int.Parse(radTextBoxFloodRequests.Text)];

        for (int i = 0; i < int.Parse(radTextBoxFloodRequests.Text); i++)
        {
            tasks[i] = new Task<int>(() =>
            {
                int x = i;
                int result = TaskRequestWithResult(int.Parse(radTextBoxFirstNumber.Text), int.Parse(radTextBoxSecondNumber.Text), int.Parse(radTextBoxFloodDelay.Text), x);
                return result;
            });
        }

        var continuation = Task.Factory.ContinueWhenAll(
                    tasks,
                    (antecedents) =>
                    {

                        int total = 0;
                        for (int i = 0; i < int.Parse(radTextBoxFloodRequests.Text); i++)
                            total = total + tasks[i].Result;
                        Debug.Print("Finished - Sum of all results is: " + total);
                        MessageBox.Show("Finished - Sum of all results is: " + total);                     
                    });


        for (int i = 0; i < int.Parse(radTextBoxFloodRequests.Text); i++)
            tasks[i].Start();
        // Use next line if you want to block the main thread until all the tasks are complete
        //continuation.Wait();


    }
    catch (Exception ex)
    {

        MessageBox.Show(ex.Message.ToString());

    }
}
4

1 に答える 1

6

ループ値を閉じています。一時変数を外側のスコープに移動する必要があります。

    for (int i = 0; i < int.Parse(radTextBoxFloodRequests.Text); i++)
    {
        int x = i; // This was in the wrong scope
        tasks[i] = new Task<int>(() =>
        {
            int result = TaskRequestWithResult(int.Parse(radTextBoxFirstNumber.Text), int.Parse(radTextBoxSecondNumber.Text), int.Parse(radTextBoxFloodDelay.Text), x);
            return result;
        });
    }

これが発生する理由の詳細については、Eric Lippert の「有害と見なされるループ変数を閉じる」を参照してください。

そうは言っても、この場合、シーケンス内の各要素に対して「タスク」を実行しています。Parallel.For目的の点でより明確になる可能性が高いため、タスクの配列の代わりに使用することを検討することをお勧めします。

int firstNum = int.Parse(radTextBoxFirstNumber.Text);
int secondNum = int.Parse(radTextBoxSecondNumber.Text);
int delay = int.Parse(radTextBoxFloodDelay.Text);
var task = Task.Factory.StartNew(() =>
{
    int total;
    Parallel.For(0, int.Parse(radTextBoxFloodRequests.Text), 
    () => 0,
    (i, loopState, localState) =>
    {
        return localState + TaskRequestWithResult(firstNum, secondNum, delay, i);
    },
    localTotal => Interlocked.Add(ref total, localTotal);

    return total;
};

var continuation = task.ContinueWith(
                antecedent =>
                {

                    int total = antecedent.Result;
                    Debug.Print("Finished - Sum of all results is: " + total);
                    MessageBox.Show("Finished - Sum of all results is: " + total);                     
                });  // Can use scheduler here if you want to update UI values
于 2013-02-11T21:47:33.423 に答える