多対多の関係でICollectionを使用し、IEnumerableまたはList <T>を使用しないのはなぜですか?


359

これは、ナビゲーションプロパティがのチュートリアルでよく見られICollection<T>ます。

これはEntity Frameworkの必須要件ですか?使用できますIEnumerableか?

ICollection代わりに、IEnumerableあるいはさらに使用する主な目的は何List<T>ですか?

回答:


440

通常、何を選択するかは、アクセスする必要のあるメソッドによって異なります。一般的に- IEnumerable<>(MSDN:http : //msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx)反復する必要があるだけのオブジェクトのリストICollection<>(MSDN:http:// msdn.microsoft.com/en-us/library/92t2ye13.aspx)(反復処理および変更List<>が必要なオブジェクトのリスト、反復処理、変更、ソートなどが必要なオブジェクトのリストについては、こちらを参照)完全なリストについては、http//msdn.microsoft.com/en-us/library/6sh2ey19.aspx)をご覧ください

より具体的な観点から見ると、遅延読み込みはタイプの選択に関係します。デフォルトでは、Entity Frameworkのナビゲーションプロパティは変更の追跡に付属しており、プロキシです。動的プロキシをナビゲーションプロパティとして作成するには、仮想タイプがを実装する必要がありますICollection

関係の「多」端を表すナビゲーションプロパティは、ICollectionを実装する型を返す必要があります。Tは、関係のもう一方の端にあるオブジェクトの型です。- POCOプロキシの作成要件MSDNを

関係の定義と管理に関する詳細情報MSDN


2
それで、それで、Listもっと良くなるはずですよね?
Jan Carlo Viray、2012

3
@JanCarloViray-私はListよく使う傾向があります。最もオーバーヘッドが大きくなりますが、ほとんどの機能を提供します。
Travis J

1
リストは、それらを並べ替える機能ではなく、インデクサーによって定義されます(整数のインデクサーを使用すると、簡単に並べ替えることができますが、必須ではありません)。
phoog 2012

2
編集に関しては、プロパティをインターフェイスタイプに制限することは、メモリではなくカプセル化に関するものです。検討:private IEnumerable<int> _integers = new List<int> { 1, 2, 3 };同じメモリを使用private List<int> _integers = new List<int> { 1, 2, 3 };
phoog 2012

13
@TravisJ:にList<T>は、のGetEnumerator()実装とは別のメソッドIEnumerable<T>があり、変更可能な構造タイプを返しますList<T>.Enumerator。ほとんどのコンテキストでは、その型はスタンドアロンのヒープオブジェクトよりもわずかに優れたパフォーマンスを発揮します。(C#とvb.netの両方のように)ダックタイプの列挙子を使用するコンパイラは、foreachコードを生成するときにこれを利用できます。場合List<T>にキャストされるIEnumrable<T>前にforeachIEnumerable<T>.GetEnumerator()この方法では不可能な最適化をレンダリング、ヒープ割り当てられたオブジェクトを返します。
スーパーキャット2012年

86

ICollection<T>これは、IEnumerable<T>インターフェースがアイテムの追加、アイテムの削除、またはその他の方法でコレクションを変更する方法を提供しないためです。


3
List <T>と比較してどうですか?
Jan Carlo Viray、2012

12
List<T>実装しICollection<T>ます。
消費者の

非ジェネリックでICollectionは、アイテムを追加する方法はありませんが、通常はすべてを列挙するよりもはるかに高速なメンバーをIEnumerable<T>提供するため、これは依然として便利な付属物ですCount。メモ場合にIList<Cat>、またはがICollection<Cat>期待コードに渡されIEnumerable<Animal>Count()それは非ジェネリックを実装する場合、拡張方法は、高速であろうICollectionが、それは唯一の一般的なインタフェースを実装しない場合は、一般的なので、ICollection<Cat>実装しないであろうICollection<Animal>
スーパーキャット2012

58

についての質問への回答List<T>

List<T>クラスです。インターフェイスを指定すると、実装の柔軟性が高まります。より良い質問は「なぜしないのIList<T>ですか?」です。

その質問に答えるために、何がIList<T>追加されるかを考えてくださいICollection<T>:整数のインデックス付け、つまりアイテムには任意の順序があり、その順序を参照することで取得できます。アイテムはおそらく異なるコンテキストで異なる順序で注文される必要があるため、これはおそらくほとんどの場合意味がありません。


21

ICollectionとIEnumerableの間にはいくつかの基本的な違いがあります

  • IEnumerable -Enumeratorを取得するためのGetEnumeratorメソッドのみを含み、ループを許可します
  • ICollectionには追加のメソッドが含まれています:Add、Remove、Contains、Count、CopyTo
  • ICollectionはIEnumerableから継承されます
  • ICollectionでは、追加/削除などのメソッドを使用してコレクションを変更できます。IEnumerableで同じことをする自由はありません。

簡単なプログラム:

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

namespace StackDemo
{
    class Program 
    {
        static void Main(string[] args)
        {
            List<Person> persons = new List<Person>();
            persons.Add(new Person("John",30));
            persons.Add(new Person("Jack", 27));

            ICollection<Person> personCollection = persons;
            IEnumerable<Person> personEnumeration = persons;

            // IEnumeration
            // IEnumration Contains only GetEnumerator method to get Enumerator and make a looping
            foreach (Person p in personEnumeration)
            {                                   
               Console.WriteLine("Name:{0}, Age:{1}", p.Name, p.Age);
            }

            // ICollection
            // ICollection Add/Remove/Contains/Count/CopyTo
            // ICollection is inherited from IEnumerable
            personCollection.Add(new Person("Tim", 10));

            foreach (Person p in personCollection)
            {
                Console.WriteLine("Name:{0}, Age:{1}", p.Name, p.Age);        
            }
            Console.ReadLine();

        }
    }

    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Person(string name, int age)
        {
            this.Name = name;
            this.Age = age;
        }
    }
}

13

私はそれをこのように覚えています:

  1. IEnumerableにはGetEnumerator()というメソッドが1つあり、コレクションの値を読み取ることはできますが、書き込むことはできません。列挙子の使用の複雑さのほとんどは、C#のfor eachステートメントによって処理されます。IEnumerableには、現在の要素を返すCurrentという1つのプロパティがあります。

  2. ICollectionはIEnumerableを実装し、Countを最も使用する追加のプロパティをいくつか追加します。ICollectionのジェネリックバージョンは、Add()メソッドとRemove()メソッドを実装します。

  3. IListはIEnumerableとICollectionの両方を実装し、整数のインデックスアクセスを項目に追加します(順序付けはデータベースで行われるため、通常は必要ありません)。


4
あなたが書いたものに基づいて、ICollectionとIListは同じです。ICollectionに存在しないIListに追加されたものを追加してください。
賭ける

ICollection VS IList、IList- IEnumerableとICollectionのすべての機能、および追加機能を含むSystem.CollectionのIList専用インターフェイス。IListにはInsertメソッドとRemoveメソッドがあります。どちらのメソッドも、パラメーターにインデックスを受け入れます。したがって、コレクションに対するインデックスベースの操作をサポートします。
E.Meir 2018

7

使用の基本的な考え方ICollectionは、有限量のデータへの読み取り専用アクセスへのインターフェースを提供することです。実際、ICollection.Countプロパティがあります。IEnumerable論理的なポイント、コンシューマーによって明示的に指定された条件、または列挙の終わりまで読み取るデータのチェーンに適しています。


14
TIL ICollectionは読み取り専用ですが、そうでICollection<T>はありません。
カールG

2

通常、ナビゲーションプロパティは仮想として定義されているため、遅延読み込みなどの特定のEntity Framework機能を利用できます。

ナビゲーションプロパティが複数のエンティティを保持できる場合(多対多または1対多の関係など)、そのタイプは、ICollectionなど、エントリを追加、削除、および更新できるリストである必要があります。

https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net- mvc-application


2

私が過去に行ったことは、リポジトリのメソッドで次の数を実行する必要があるかどうかに応じてIList<Class>ICollection<Class>またはIEnumerable<Class>(静的リストの場合)を使用して内部クラスコレクションを宣言します:列挙、並べ替え/順序付け、または変更。オブジェクトを列挙する(そしておそらく並べ替える)必要がある場合はList<Class>、IEnumerableメソッド内でコレクションを操作するためのtempを作成します。この方法は、コレクションが比較的少ない場合にのみ効果的だと思いますが、一般的には、idkは良い方法です。これがなぜ良い習慣にならないのかについての証拠があるなら、私を訂正してください。


0

ロジックのある/外のボックスの外側で考えてみて、質問のこれら3つのインターフェースを明確に理解しましょう:

あるインスタンスのクラスがSystem.Collection.IEnumerableインターフェースを実装する場合、簡単に言えば、このインスタンスは列挙可能であり反復可能でもあります。つまり、このインスタンスは単一ループでgo / get / pass /このインスタンスに含まれるすべてのアイテムと要素をトラバース/反復します。

つまり、このインスタンスに含まれるすべてのアイテムと要素を列挙することもできます。

System.Collection.IEnumerableインターフェイスを実装するすべてのクラスは、引数を取らずにSystem.Collections.IEnumeratorインスタンスを返すGetEnumeratorメソッドも実装します。

System.Collections.IEnumeratorインターフェイスのインスタンスの動作は、C ++イテレータと非常によく似ています。

あるインスタンスのクラスがSystem.Collection.ICollectionインターフェイスを実装している場合、簡単に言えば、このインスタンスは何かのコレクションであると言えます。

このインターフェイスのジェネリックバージョン、つまりSystem.Collection.Generic.ICollectionは、コレクション内のモノのタイプが何であるかを明示的に示すため、より有益です。

これはすべて合理的、合理的、論理的であり、System.Collections.ICollectionインターフェイスがSystem.Collections.IEnumerableインターフェイスから継承されることは理にかなっています。理論的にはすべてのコレクションも列挙可能であり、反復可能であり、理論的にはすべてのアイテムと要素を調べることが可能です。すべてのコレクションで。

System.Collections.ICollectionインターフェイスは、変更可能な有限の動的コレクションを表します。つまり、既存のアイテムをコレクションから削除したり、新しいアイテムを同じコレクションに追加したりできます。

これは、System.Collections.ICollectionインターフェイスに「追加」および「削除」メソッドがある理由を説明しています。

System.Collections.ICollectionインターフェイスのそのインスタンスは有限のコレクションであるため、「有限」という言葉は、このインターフェイスのすべてのコレクションが常に有限の数のアイテムと要素を持つことを意味します。

System.Collections.ICollectionインターフェイスのプロパティCountは、この数を返すことを想定しています。

System.Collections.IEnumerableインターフェイスには、System.Collections.ICollectionインターフェイスにあるこれらのメソッドとプロパティがありません。これは、System.Collections.IEnumerableがSystem.Collections.ICollectionインターフェイスにあるこれらのメソッドとプロパティを持つことには意味がないためです。

ロジックはまた、列挙可能で反復可能であるすべてのインスタンスが必ずしもコレクションである必要はなく、必ずしも変更可能である必要もないことを示しています。

変更可能と言っても、列挙可能で反復可能であるものに何かを追加したり削除したりできるとすぐに考えないでください。

たとえば、有限数の素数のシーケンスを作成した場合、この有限数の素数のシーケンスは、実際にはSystem.Collections.IEnumerableインターフェイスのインスタンスです。これにより、この有限シーケンスのすべての素数を1つのループで処理できるようになります。そして、それぞれをコンソールウィンドウや画面に出力するなど、それぞれにやりたいことをすべて行いますが、この有限の素数のシーケンスはSystem.Collections.ICollectionインターフェイスのインスタンスではありません。これは意味がないからです。この有限の素数のシーケンスに合成数を追加します。

また、次の反復で、現在の素数に現在最も近い素数に次に最も近い素数を取得する必要がある場合は、この有限の素数のシーケンスから既存の素数を削除する必要もありません。

また、おそらくSystem.Collections.IEnumerableインターフェイスのGetEnumeratorメソッドで "yield return"を使用してコーディングし、メモリヒープに何も割り当てずに素数を生成してから、両方にガベージコレクタ(GC)を割り当てます。これは明らかにオペレーティングシステムのメモリの浪費であり、パフォーマンスを低下させるため、このメモリの割り当てを解除してヒープから解放します。

ヒープの動的メモリ割り当てと割り当て解除は、System.Collections.ICollectionインターフェイスのメソッドとプロパティを呼び出すときに行う必要がありますが、System.Collections.IEnumerableインターフェイスのメソッドとプロパティを呼び出すときは行わないでください(System.Collections.IEnumerableインターフェイスには1つのメソッドと0のプロパティ)。

このスタックオーバーフローWebページで他の人が言ったことによると、System.Collections.IListインターフェイスは単に注文可能を表しますコレクションをあり、これがSystem.Collections.IListインターフェイスのメソッドがSystem.Collections.ICollectionインターフェイスのメソッドとは対照的にインデックスで機能する理由を説明しています。

要するに、System.Collections.ICollectionインターフェイスは、そのインスタンスが順序付け可能であることを意味しませんが、System.Collections.IListインターフェイスはそれを意味します。

理論的に順序付けられたセットは、順序付けられていないセットの特殊なケースです。

これは理にかなっており、System.Collections.IListインターフェイスがSystem.Collections.ICollectionインターフェイスを継承する理由も説明しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.