1

次のコードがあるとします。

List<Category> categories = getCategories();
List<Category> unusedCategories = categories;
    foreach (var category in categories)
        foreach (var imageCategory in image.Categories)
            if (category.CategoryID == imageCategory.CategoryID)
                unusedCategories.Remove(category);

ループ中にコレクションが変更されているというエラーが発生しました。確かに、デバッガーをステップ実行したとき、remove(category) が使用された場合、「categories」リストは以前よりも 1 要素短くなりました。「unusedCategories」から削除すると「categories」に影響するのはなぜですか? それらは、同じものを参照するのではなく、2 つの別個のリストである必要があります。.Remove() 関数は値渡しですよね?それで、これはどのように起こりますか?

注: 上記で行っていることに対するプログラムによる代替手段があることは知っており、既に採用しています。なぜこれが起こっているのか興味があります。

4

2 に答える 2

9

同じものを参照するのではなく、2 つの異なるリストにする必要があります。

本当じゃない。に代入categoriesすると、参照によってunusedCategories代入されます。

コピーが必要な場合は、リストのコピーを明示的に作成する必要があります。

List<Category> unusedCategories = new List<Category>(categories);

より効率的な代替手段として、次のようなものを検討できます。

HashSet<int> usedCategoryIds = new HashSet<int>(image.Categories.Select(c => c.CategoryID));

List<Category> categories = getCategories();
List<Cagegory> unusedCategories = categories.Where(c => !usedCategoryIds.Contains(c => c.CategoryID)).ToList();
于 2012-08-31T18:31:46.517 に答える
0

LINQたとえば、次のようにします。

var removables = from category in categories
                        join imageCategory in image.Categories 
                              on category.CategoryID equals 
                                 imageCategory.CategoryID  select category;

そして削除後

 unusedCategories.RemoveAll(removables );

または、for取得した例外を回避するためにループを使用できます。

または @Reed: で記述されたパスをたどって、両方のコレクションの参照依存関係を切り離します。

于 2012-08-31T18:35:27.323 に答える