パブリックAPIのメソッドとプロパティからどのコレクション型を返すべきか混乱しています。
私が念頭に置いているコレクションはIList
、ICollection
とCollection
です。
これらのタイプの1つを返すことは常に他のタイプよりも優先されますか、それとも特定の状況に依存しますか?
パブリックAPIのメソッドとプロパティからどのコレクション型を返すべきか混乱しています。
私が念頭に置いているコレクションはIList
、ICollection
とCollection
です。
これらのタイプの1つを返すことは常に他のタイプよりも優先されますか、それとも特定の状況に依存しますか?
回答:
一般に、可能な限り一般的なタイプ、つまり、コンシューマが使用する必要がある、返されたデータを十分に把握しているタイプを返す必要があります。これにより、APIを使用しているコードを壊すことなく、APIの実装をより自由に変更できます。
IEnumerable<T>
インターフェースも戻り値の型と見なしてください。結果が反復されるだけの場合、消費者はそれ以上必要としません。
Count
メソッドの実装はコレクションの実際のタイプをチェックするため、配列などのいくつかの既知のタイプのLength
またはCount
プロパティを使用しICollection
ますIEnumerable
。
Thing<T>
道具IList<T>
ではなく、非ジェネリックICollection
、その後の呼び出しIEnumerable<Cat>.Count()
にはThing<Cat>
速くなりますが、呼び出し元がIEnumerable<Animal>.Count()
拡張メソッドを見つけるために見て、ではないであろうから、(の実装遅くなりますICollection<Cat>
)。ICollection
ただし、クラスがnon-genericを実装している場合は、それIEnumerable<Animal>.Count
を見つけて使用します。
ICollection<T>
以下のようなコレクションのセマンティクスを公開するインターフェイスがありAdd()
、Remove()
とCount
。
Collection<T>
ICollection<T>
インターフェースの具体的な実装です。
IList<T>
本質的にICollection<T>
はランダムな順序ベースのアクセスです。
この場合、結果に順序ベースのインデックス付けなどのリストのセマンティクスがIList<T>
必要かどうか(次に使用)、または結果の順序付けされていない「バッグ」を返す必要があるかどうか(その後に使用)を決定する必要がありますICollection<T>
。
Collection<T>
実装するIList<T>
だけでなくICollection<T>
。
IEnumerable<T>
は、順序付けされているため、順序付けされています。どのような区別IList<T>
からすると、ICollection<T>
それがインデックスで動作するようにメンバーを提供することです。たとえば、list[5]
動作しますが、collection[5]
コンパイルされません。
IList<T>
。順序付けられていないコレクションがたくさんあります。IList<T>
高速インデックスアクセスについてです。
IEnumerable<T>
が注文されていますか?取るHashSet<T>
-それは実装されますIEnumerable<T>
が、明らかに注文されていません。つまり、アイテムの順序には影響がなく、内部ハッシュテーブルが再編成された場合、この順序はいつでも変更される可能性があります。
主な違いIList<T>
とはICollection<T>
つまりIList<T>
、あなたがインデックスを経由してアクセス要素にできます。IList<T>
配列のような型を記述します。の要素には、ICollection<T>
列挙によってのみアクセスできます。どちらも要素の挿入と削除ができます。
コレクションを列挙するだけでよい場合IEnumerable<T>
は、が推奨されます。他の2つの利点があります。
コレクションへの変更を許可しません(参照タイプの場合、要素への変更は許可しません)。
アルゴリズムによって生成され、コレクションではない列挙を含む、可能な限り最大のさまざまなソースを許可します。
Collection<T>
コレクションの実装者に主に役立つ基本クラスです。インターフェース(API)で公開すると、そこから派生しない多くの有用なコレクションが除外されます。
欠点の1つIList<T>
は、配列がそれを実装しているが、項目を追加または削除できないことです(つまり、配列の長さを変更できない)。IList<T>.Add(item)
配列を呼び出すと、例外がスローされます。IList<T>
ブール型のプロパティがIsReadOnly
あるので、そうする前にチェックできるので、状況はやや混乱しています。しかし、私の目には、これはまだライブラリの設計上の欠陥です。したがって、List<T>
アイテムを追加または削除する可能性が必要な場合は、直接使用します。
Collection
、ReadOnlyCollection
またはKeyedCollection
。そして、それList
は返されるべきではありません。
IList<T>
、メソッドが配列をパラメータとして呼び出されないようにする方法はありません。
IList<T>
すべての総称リストの基本インターフェースです。これは順序付けられたコレクションであるため、実装は、ソートされた順序から挿入順序まで、順序を決定できます。さらにIlist
、メソッドがインデックスに基づいてリストのエントリを読み取り、編集できるようにするItemプロパティがあります。これにより、位置インデックスのリストに値を挿入したり、リストから値を削除したりできます。
また、からIList<T> : ICollection<T>
、のすべてのメソッドICollection<T>
もここで実装に使用できます。
ICollection<T>
すべてのジェネリックコレクションの基本インターフェイスです。サイズ、列挙子、同期方法を定義します。コレクションに項目を追加または削除することはできますが、インデックスプロパティがないため、それが発生する位置を選択することはできません。
Collection<T>
以下のための実装を提供しIList<T>
、IList
そしてIReadOnlyList<T>
。
のICollection<T>
代わりにIList<T>
、より狭いインターフェイスタイプを使用すると、破壊的な変更からコードを保護できます。のようなより広いインターフェイスタイプを使用するとIList<T>
、コードの変更を壊す危険性が高まります。
ソースからの引用、
ICollection
、ICollection<T>
:コレクションを変更するか、コレクションのサイズを気にします。IList
、IList<T>
:コレクションを変更し、コレクション内の要素の順序や配置に注意します。
インターフェースタイプを返すことはより一般的であるため、(特定のユースケースに関する詳細な情報を欠いている)私はそれに傾倒します。インデックス作成のサポートを公開するIList<T>
場合ICollection<T>
は、を選択します。それ以外の場合は十分です。最後に、返された型が読み取り専用であることを示すには、を選択しますIEnumerable<T>
。
また、これまでに読んだことがない場合は、Brad AbramsとKrzysztof Cwalinaが「再利用可能な.NETライブラリのフレームワーク設計ガイドライン:慣習、慣用句、およびパターン」というタイトルの優れた本を執筆しました(ここからダイジェストをダウンロードできます)。
IEnumerable<T>
読み取り専用ですか?もちろん、リポジトリのコンテキストで再調整する場合、ToListを実行した後でもスレッドセーフではありません。問題は、元のデータソースがGCを取得したときに、IEnumarble.ToList()がマルチスレッドコンテキストで機能しないことです。それはあなたが仕事をした後にGCが呼び出されるので線形1で動作しますが、async
現在4.5+ IEnumarbaleでの日数を使用することは簡単ではありません。
この質問から来るいくつかの主題があります:
オブジェクト指向APIであることを強調したい場合があります
インターフェースとクラス
インターフェースの経験があまりない場合は、クラスを使用することをお勧めします。必要ではないにせよ、多くの場合、開発者はインターフェースにジャンプします。
そして、良いクラスデザインの代わりに、質の悪いインターフェイスデザインをやめることです。ちなみに、最終的には優れたインターフェイスデザインに移行できます...
APIには多くのインターフェースが表示されますが、必要がなければ、急いでそれを実行しないでください。
最終的には、インターフェースをコードに適用する方法を学びます。
いくつかの類似したクラス、コレクション、リスト、配列から、どの特定のクラスですか?
c#(dotnet)には、交換可能なクラスがいくつかあります。すでに述べたように、「CanBeSortedClass」などのより具体的なクラスから何かが必要な場合は、APIで明示的にしてください。
APIユーザーは、クラスを並べ替えたり、要素に何らかの形式を適用したりできることを本当に知っている必要がありますか?次に、「CanBeSortedClass」または「ElementsCanBePaintedClass」を使用します。それ以外の場合は、「GenericBrandClass」を使用します。
それ以外の場合は、より一般的なクラスを使用します。
一般的なコレクションクラスとサブアイテム(「ジェネリック」)コレクション
他の要素を含むクラスがあり、すべての要素が特定のタイプであることを指定できます。
ジェネリックコレクションは、あなたがこのように、それぞれの新しいサブ項目タイプのために、新しいコレクションを作成することなく、いくつかのコードアプリケーションのために、同じコレクションを使用することができ、それらのクラスです:コレクション。
APIユーザーは、すべての要素に対して同じように、非常に具体的なタイプを必要とするでしょうか?
のようなものを使用してくださいList<WashingtonApple>
。
あなたのAPIユーザーはいくつかの関連するタイプを必要とするでしょうか?
公開List<Fruit>
あなたのAPIのために、使用List<Orange>
List<Banana>
、List<Strawberry>
内部的に、どこOrange
、Banana
とStrawberry
の子孫ですFruit
。
あなたのAPIユーザーはジェネリック型コレクションを必要としていますか?
使用List
すべての項目があり、object
(S)。
乾杯。