2

タイトルごとに-IListまたはIDictionaryでのフェイルセーフ反復のためのC#/。NETの優れた組み込みオプションはありますか?

私が問題にぶつかっているのは、次のようなコードです。

IList<Foo> someList = new List<Foo>();

//...

foreach (Foo foo in someList) {
  if (foo.Bar) {
    someList.remove(foo);
  }
}

これは、foo.Barが最初にtrueになった後に次をスローします。

Type: System.InvalidOperationException
Message: Collection was modified; enumeration operation may not execute.

簡単な回避策は実行することですforeach (Foo foo in new List<Foo>(someList))が、それを毎回実行することを覚えておく必要があるのは面倒です。独身。時間。これが出てきます。

Javaのバックグラウンドから来ているので、CopyOnWriteArrayList / ConcurrentHashMapで適切に処理できます(これらのリストの使用に関連する他のペナルティがあることを認識しています)。C#に、私が気付いていない同等のものはありますか?

4

7 に答える 7

2

.NET 4を使用している場合は、ConcurrentDictionary<TKey, TValue>と(および同じ名前空間ConcurrentBag<T>内のキューとスタック)があります。しかし、私が知る限り、実装するものは何もありません。IList<T>

于 2010-10-26T19:53:17.560 に答える
2

LINQ を楽しんでみませんか。List の動作は変更しませんが、コードの記述が改善されます。もちろん、これは IList ではなく List でのみ機能しますが、それでもクールです。

someList.RemoveAll(Foo => Foo.Bar == true);
于 2010-10-26T20:04:17.367 に答える
0

あなたが探しているのは、堅牢な iteratorと呼ばれるものです。IEnumerable<T>イテレータ パターンは、 およびを介して .NET に実装されますIEnumerator<T>

デフォルトでは、Base Class Library で取得する反復子は堅牢ではありません。ただし、自分で作成することはできます。同じ要素を 2 回調べたり、要素をスキップしたりしないようにする必要があるため、実装するのは少し難しいでしょう。しかし、それは確かに可能です。

から派生するカスタム クラスを作成する場合List<T>、メソッドをオーバーライドして堅牢な反復子GetEnumerator()を返すことができるため、構文を使用できます。foreach

于 2010-10-26T20:07:49.070 に答える
0

VB.net には、VB6 スタイルのコレクションを実装する Collection というクラスがあります。いくつかの点でかなり間抜けですが(常にコレクション(Of String、Object)です)、その列挙子は説明どおりに使用でき、そのパフォーマンスはかなり高速です。大文字と小文字を区別しない文字列比較を使用しており、Microsoft が汎用バージョンを作成してくれればよかったのですが、その列挙動作はニーズに合っている可能性があり、適切な名前空間をインポートすれば C# で使用できるはずだと思います。

于 2010-10-26T20:20:24.553 に答える
0

繰り返し処理中に変更を処理し、どの項目を繰り返し処理する必要があるかを判断できるリストまたは辞書は、非常に複雑になります。ほとんどの状況は想像できる最悪の状況よりもはるかに単純であるため、状況ごとに解決することをお勧めします。

たとえば、次のようにすることができます。

someList.Where(foo => foo.Bar).ToList().ForEach(foo => someList.remove(foo));

ほとんどの場合、最初にリスト全体をコピーするよりも効率的です。通常、削除されるアイテムはかなり少ないからです。

于 2010-10-26T20:02:30.277 に答える
0

コレクションの変更に関する問題を解決する簡単な方法は、削除するアイテムのリストをクエリし、これらのアイテムのリストを反復処理することです。

using System.Collections.Generic;
using System.Linq;

class Foo
{
    public bool Bar { get; set; }
}

class Program
{
    static void Main()
    {
        IList<Foo> someList = new List<Foo>() {
            new Foo() { Bar = true },
            new Foo() { Bar = false },
            new Foo() { Bar = true }
        };

        var itemsToRemove = someList.Where(f => f.Bar == true).ToArray();

        foreach (var foo in itemsToRemove)
        {
            someList.Remove(foo);
        }
    }
}
于 2010-10-26T19:58:23.333 に答える