3

「インデックスが配列の境界外でした」というこのコードがあります。i変数は常に配列の長さよりも小さくなければならblaないため、このエラーが発生しないため、なぜこれが起こっているのかわかりません。

private void buttonDoSomething_Click(object sender, EventArgs e)
{
    List<Thread> t = new List<Thread>();

    string[] bla = textBoxBla.Lines;

    for (int i = 0; i < bla.Length; i++)
    {
        t.Add(new Thread (() => some_thread_funmction(bla[i])));
        t[i].Start();
    }
}

誰かがこれを修正する方法と、なぜこれが起こっているのか教えてもらえますか. ありがとう!

4

2 に答える 2

10

閉鎖はここであなたの問題です。

基本的に、(ループ内で) ラムダを作成するときに値を取得するのではなく、必要なときに値を取得します。そして、コンピューターは非常に高速であるため、それが起こる頃には、すでにループから外れています。値は 3 です。以下に例を示します (まだ実行しないでください)。

private void buttonDoSomething_Click(object sender, EventArgs e)
{
    List<Thread> t = new List<Thread>();
    for (int i = 0; i < 3; i++)
    {
        t.Add(new Thread (() => Console.Write(i)));
        t[i].Start();
    }
}

結果がどうなるかを考えてみてください。考えているのでは012ないでしょうか?

今すぐ実行してください。

結果は になります333

これを修正する変更されたコードを次に示します。

private void buttonDoSomething_Click(object sender, EventArgs e)
{
    List<Thread> t = new List<Thread>();
    string[] bla = textBoxBla.Lines;
    for (int i = 0; i < bla.Length; i++)
    {
        int y = i; 
        //note the line above, that's where I make the int that the lambda has to grab
        t.Add(new Thread (() => some_thread_funmction(bla[y]))); 
        //note that I don't use i there, I use y.
        t[i].Start();
    }
}

これでうまくいきます。今回は、ループが終了すると値が範囲外になるため、ラムダはループが終了する前に取得するしかありません。これにより、期待される結果が得られ、例外はありません。

于 2013-05-30T18:39:47.347 に答える
2

あなたが見ているのは競合状態です。スレッドforが実際に開始する前に、ループが完了しています。そのため、スレッドが実際に開始するまでに、 の値はi配列の範囲外になります。

インデックス値をコピーして、代わりにコピーを渡してみてください。

private void buttonDoSomething_Click(object sender, EventArgs e)
{
    List<Thread> t = new List<Thread>();

    string[] bla = textBoxBla.Lines;

    for (int i = 0; i < bla.Length; i++)
    {
        int index = i;
        t.Add(new Thread (() => some_thread_funmction(bla[index])));
        t[i].Start();
    }
}
于 2013-05-30T18:39:55.243 に答える