2

問題を引き起こしている次のコードがあります。助けていただければ幸いです。

private static string CreateOptionString(List<VehicleOption> Options)
{
    StringBuilder returnValue = new StringBuilder();
    foreach (VehicleOption option in Options)
    {
        if (option.OptionStatus == ExtendedResponse.OptionState.Included)
        {
            if (returnValue.Length > 0)
            {
                returnValue.Append(", ");
            }
            returnValue.Append(option.OptionName);
        }
    }
    return returnValue.ToString();
}

私の最初の問題は、 foreach ループで System.InvalidOperationException: collection was modified エラーが発生したことでした。

1)変更された場所がどこにもないため、なぜこのエラーが発生するのかまだわかりません。

リストを新しいリストにコピーして、新しいリストをループすることを誰かが提案しました。私はそれを行い、InvalidOperationExceptionを取り除きました。ただし、リストを2つの異なる方法で対処しようとしましたが、どちらも System.ArgumentException: Destination array was not long十分な長さでした。リストをコピーしようとした2つの方法は次のとおりです

List<VehicleOption> newOptions = new List<VehicleOption>(Options);

List<VehicleOption> newOptions = new List<VehicleOption>();
newOptions.AddRange(Options);

これらはどちらも私に System.ArgumentException: Destination array was not long enough を与えました。

2)これらの方法のいずれかで例外が発生するのはなぜですか?

私は困惑しているので、助けていただければ幸いです。

ありがとう!

4

3 に答える 3

5

コレクションが繰り返されている間、他のスレッドがコレクションを変更していないことを確認してください。

また、それを行う別の方法は次のとおりです。

return string.Join(", ", options.Where(
    op => op.OptionStatus == ExtendedResponse.OptionState.Included));

この場合、StringBuilderを使用するよりも優れており、(驚くべきことに)高速です。

それでも、これでは問題は解決しません。これは、コレクションを変更する別のスレッドが原因である可能性があります。

私の最初の試みは次のようになります:

private static string CreateOptionString(List<VehicleOption> Options)
{
    lock (Options)
    {
        return string.Join(", ", options.Where(
            op => op.OptionStatus == ExtendedResponse.OptionState.Included));
    }
}

しかしもちろん、他のスレッドがそのコレクションをいじり回しているという情報があれば、より優れたスレッドセーフなソリューションを提供する方が簡単だったでしょう。

于 2012-06-12T22:46:18.800 に答える
4

によって参照されているリストオブジェクトOptionsが別のスレッドによって変更されているようです。これは両方の問題を説明します。

  1. 明らかに、反復中に別のスレッドがリストを変更すると、要素が列挙されている間はリストを変更できないため、「コレクションが変更されました」という例外が発生します。
  2. 後者の場合、コンストラクターのように聞こえAddRange、配列を割り当ててから、提供された列挙型から配列を埋めます。リストが割り当ての間に大きくなり、新しい配列を満たすために列挙された場合、突然、割り当てられたストレージが十分に大きくなりなくなり、この動作が発生します。

このコードが要素を処理している間、または後で処理するためにコピーを作成している間、リストに書き込んでいる可能性のあるスレッドをブロックできるように、いくつかのロックメカニズムを設計する必要があります。

于 2012-06-12T22:46:06.087 に答える
0

わかりました、私は問題を解決しました。メソッドの呼び出しの周りに (オプション リストに) ロックを設定しました。これにより、すべての問題が修正されました。

みんな、ありがとう!

于 2012-06-14T16:27:22.740 に答える