この質問への回答で、 runefsは、「IListを使用する特別な理由がない限り、IEnumerableを検討する必要がある」と提案しました。どちらを使用しますか、またその理由は何ですか?
6 に答える
IEnumberable<T>
は読み取り専用です。コレクションに変更を加えるには、コレクションを再構築する必要があります。一方、IList<T>
は読み取り/書き込みです。したがって、コレクションに多くの変更が予想される場合は公開IList<T>
しますが、変更しないと想定しても安全な場合は、を使用してくださいIEnumerable<T>
。
後で実装を変更するための柔軟性が最も高くなるため、必要な機能を提供する最も制限の厳しいインターフェースを常に使用してください。したがって、IEnumerable<T>
十分な場合はそれを使用します...リスト機能が必要な場合は、を使用しますIList<T>
。
そして、できれば強く型付けされた汎用バージョンを使用してください。
私が従う原則は、しばらく前に読んだものです。
「最も単純なものを消費し、最も複雑なものを公開する」
(これは本当に一般的であり、引用を誤っていると確信しています。誰かがソースを知っている場合は、コメントを残すか編集してください...)
(追加するために編集されました-まあ、ここで私は数週間後、まったく異なるコンテキストでこの引用に出くわしました.ロバストネス原則またはポステルの法則として始まったようです-
何をするにも保守的であること。他者から受け入れるものに寛大であること。
元の定義はインターネットを介したネットワーク通信用ですが、OO でクラス コントラクトを定義するために再利用されているのを見たことがあると確信しています。)
基本的に、外部消費用のメソッドを定義している場合、パラメーターは必要な機能を提供する最も基本的な型である必要があります。例の場合、これは IList の代わりに IEnumerable を取得することを意味する場合があります。これにより、クライアント コードは何を渡すことができるかについて最も柔軟になります。一方、外部で使用するためにプロパティを公開する場合は、最も複雑な型 (IEnumerable ではなく IList または ICollection) を使用してください。オブジェクトの使用方法の柔軟性。
コメントで私自身と DrJokepu との間の会話が魅力的であることに気付きましたが、これがディスカッション フォーラムではないことも理解しています。そのため、回答を編集して、傾向に逆らうという選択の背後にある理由をさらに概説します。それを IList として公開することをお勧めします (後でわかるように、実際には List です)。これが私たちが話しているクラスだとしましょう:
public class Example
{
private List<int> _internal = new List<int>();
public /*To be decided*/ External
{
get { return _internal; }
}
}
まず、External を IEnumerable として公開していると仮定しましょう。他の回答とコメントでこれを行う理由は、現在次のとおりです。
- IEnumerable は読み取り専用です
- IEnumerable は事実上の標準です
- カップリングを減らすため、実装を変更できます
- 実装の詳細を公開しません
IEnumerable は、読み取り専用にしない読み取り専用機能のみを公開します。返される実際の型は、リフレクションまたは単にデバッガーを一時停止して見ることで簡単に見つけられるため、List<> にキャストし直すのは簡単です。以下のコメントの FileStream の例にも同じことが当てはまります。メンバーを保護しようとしている場合、それが何か他のものであるふりをすることは、それを行う方法ではありません.
私はそれが事実上の標準であるとは信じていません。.NET 3.5 ライブラリには、具体的なコレクションを返すオプションがあり、代わりにインターフェイスを返すコードが見つかりません。IEnumerableは、LINQ のおかげで 3.5 でより一般的になっていますが、それは、より派生した型を公開できないためであり、公開したくないからではありません。
さて、私が同意する結合を減らす - ある点まで - 基本的に、この議論は、あなたが返すオブジェクトはリストですが、あなたが変更することに決めた場合に備えて、IEnumerableとして扱いたいとクライアントに伝えているようです.内部コードは後で。これに関する問題と、とにかく実際の型が公開されているという事実を無視すると、「なぜ IEnumerable で止まるのですか?」という疑問が残ります。オブジェクト型として返す場合は、実装を自由に変更できます。これは、クライアント コードに必要な機能の量について決定を下す必要があるため、クライアント コードを作成するか、任意のメトリックに基づいて決定する必要があることを意味します。
最後に、前述のように、実装の詳細は常に.NET で公開されていると想定できます。特に、オブジェクトを公開している場合はそうです。
それで、その長い批判の後に、1 つの質問が残っています - なぜそれを List<> として公開するのですか? さて、なぜですか?オブジェクトを IEnumerable として公開しても何も得られないのに、クライアント コードがオブジェクトを操作する機能を人為的に制限するのはなぜでしょうか? Microsoft が、Winforms コントロールの Controls コレクションを ControlCollection ではなく IEnumerable として表示する必要があると判断した場合を想像してみてください。IList を必要とするメソッドにそれを渡すことも、任意のインデックスでアイテムを処理することも、またはそれを確認することもできなくなります。キャストしない限り、特定のコントロールが含まれています。Microsoft が実際に得たものは何もなく、あなたに迷惑をかけるだけです。
子を列挙するだけでよい場合は、IEnumerableを使用します。Countが必要な場合は、ICollectionを使用します。ただし、実装の詳細が公開されるため、これは避けようとしています。
IList<T>
確かに非常に頑丈なインターフェースです。私は派生型を公開することを好みCollection<T>
ます。これは、Jeffrey Richterが提案していることとほぼ一致しています(近くに本がないため、ページ/章番号を指定できません)。メソッドは、最も一般的な型をパラメーターとして受け入れ、最も「派生した」型を次のように返す必要があります。戻り値。
読み取り専用コレクションがプロパティを介して公開されている場合、それを行う従来の方法は、そこにあるものをすべてラップする ReadOnlyCollection (またはその派生クラス) として公開することです。IList のすべての機能をクライアントに公開しますが、読み取り専用であることを非常に明確にします。