2009-03-05 7 views
4

のような具体的なクラスを使用する必要がありますか?私は最近、これについて別の場所で*の意見を述べましたが、詳細な分析が必要なので、独自の質問として投稿しています。IEnumerableのようなインターフェイス、またはList <>

私のプログラムでコンテナを作成して渡す必要があるとしましょう。私はおそらく、この段階で少なくとも1種類の容器と他の種類の容器について強い意見を持っていませんが、私は1つを選択します。議論のために、リスト<>を使用するとします。

質問があります:C#のような高レベルのインターフェイスを受け入れて返すメソッドを書く方が良いですか?IEnumerable?または、私が選択した特定のコンテナクラスを取得して渡すメソッドを記述する必要があります。

私はどのような要因を決定する必要がありますか?どのようなプログラムがどちらから利益を得るのですか?コンピュータ言語はあなたの決定に影響しますか?パフォーマンス?プログラムサイズ?個人的なスタイル?

(それも重要ですか?)

**(宿題:。それを見つけるしかし、あなたは自分を探して前にそうではないバイアスとして、あなたをここにあなたの答えを投稿してください。)*

答えて

5

のみあなたの決定に影響を与えるべきことは、どのようにパラメータを使用するかということです。それを反復する場合は、IEnumerable<T>を使用してください。あなたがインデックスメンバーにアクセスしている場合(例えば​​)、何らかの方法でリストを変更する場合(list.Add(x))、ICollection<T>またはIList<T>を使用してください。

16

あなたのメソッドは、その関数を実行するために必要な最小限の型を常に受け​​入れるべきです。メソッドを列挙する必要がある場合は、IEnumerableを受け入れます。定義してIList<>固有のものを行う必要がある場合は、IList<>を指定する必要があります。

+0

同意しましたが、私のコードではIEnumerableを使用するのが厄介だと感じているので、まったく同じ質問をしています。 List の代わりにfoos = fooQuery.GetFoos()を使用すると、リスト foos = new List (fooQuery.GetFoos())になります。何か不足していますか?それとも、これが柔軟性のために支払う価格ですか? – si618

+0

上記のコメントを使用した例は、結果を検証するユニットテストです。 IList.Count、実際の使用法は実際にIListを必要とせず、IEnumerableで十分ですが、ちょっと気分が悪いです... – si618

+0

@Si私たちはここでさまざまなことを話していると思います。この質問は、メソッド内のスコープについてのみです。メソッド以外の戻り値の型と使用方法について説明しています。 –

0

問題はありますが、正しい解決策は使用方法に完全に依存します。単純な列挙を行う必要がある場合は、必要な機能にアクセスするために実装者を渡すことができるようにIEnumerableを使用してください。しかし、リストの機能が必要で、メソッドの呼び出しのたびにリストの新しいインスタンスを作成する必要がないようにしたい場合、渡されたenumerableはリストではありませんでした。

3

常にトレードオフがあります。一般的な経験則では、可能な限り階層構造の上に物事を宣言することです。したがって、IEnumerableのメソッドへのアクセスが必要な場合は、それを使用する必要があります。

SOの質問の別の最近の例は、ファイル*(またはファイル記述子)の代わりにファイル名をとったC APIです。ファイル名は、渡される可能性のあるものが制限されています(ファイル記述子で渡すことができる多くのものがありますが、ファイル名を持つものだけです)。

キャストを開始した後、高すぎるか、より具体的なタイプの2番目の方法を作成する必要があります。

私が考えることができる唯一の例外は、速度が絶対必要であり、仮想メソッド呼び出しの費用を払わないことです。特定の型を宣言すると、仮想関数のオーバヘッドがなくなります(言語/環境/実装に依存しますが、一般的な記述である可能性があります)。

0

私は同様のC#質問hereに答えました。私はあなたがいつもできる最も簡単な契約を提供するべきだと思っています。私の考えでは、コレクションの場合、通常はTの数えがIEnumerableです。

実装は、内部BCLタイプetcetera - 必要なメンバーがあなたのタイプによって公開されています。

あなたの抽象型は、あなたの具体的な型によって実装される単純なBCL型を継承することができます。これは私の意見では、LSPに従うのが簡単です。

3

私はこの質問を聞いたので、ユーロミッレリはすでに自分の答えを知っていましたが、ここにあります! :)

私はオブジェクトにLinqはすでにこの質問に素晴らしい答えを提供すると思います。できるだけシンプルなインターフェースを使用することで、シーケンスを実装する方法を最大限柔軟に行うことができ、遅延の発生を防ぐことができ、パフォーマンスを犠牲にすることなく生産性を向上させることができます。

時期尚早な抽象化にはコストがかかることは事実ですが、主に新しい抽象化を発見したり発明したりするコストです。しかし、すでに完全に優れたものがあれば、それを利用しないのは夢中になります。それが、ジェネリックコレクションインターフェイスが提供するものです。

クラスにアクセスする必要がある場合に備えて、クラス内のすべてのデータをパブリックにすることが簡単にできると言う人がいます。同じように、ユーロは、IList<T>(または具象クラスList<T>)のようなコンテナに豊富なインターフェイスを使用し、後で混乱を取り除く方が良いとアドバイスしました。

しかし、アクセスしたくないクラスのデータメンバーを非表示にして、すぐにそのクラスの実装を後で簡単に変更できるようにするのがよいので、最も簡単なインターフェイス一連の項目を参照するために使用できます。実際には、簡単で基本的なものを公開し、後でそれを「緩める」ことから始めるほうが簡単です。

したがって、IEnumerable<T>がシーケンスを表すことを想定します。 AddまたはRemoveのアイテムが必要ですが(インデックスインデックスの参照は不要です)IContainer<T>を使用してください。これはIEnumerable<T>を継承し、他のコードと完全に相互運用可能です。

このようにして、このコードはデータで何ができるのかを完全にはっきりと確認できます。

小さなプログラムでは抽象度が低い必要があります。しかし、成功すれば、大きなプログラムになる傾向があります。これは、最初に単純な抽象化を採用する方がずっと簡単です。