4

私は最近、これについて別の場所で私の見解を表明しました* が、さらなる分析に値すると思うので、これを独自の質問として投稿しています。

プログラムでコンテナを作成して渡す必要があるとしましょう。少なくともこの段階では、コンテナの種類と別の種類について強い意見を持っているわけではありませんが、1 つを選びます。議論のために、 List<>を使用するとしましょう。

問題は、C# のIEnumerableなどの高レベルのインターフェイスを受け入れて返すメソッドを作成する方がよいでしょうか? または、選択した特定のコンテナー クラスを受け取って渡すメソッドを作成する必要があります。

決定するためにどのような要素と基準を探す必要がありますか? どちらか一方から恩恵を受けるのは、どのような種類のプログラム作業ですか? コンピュータ言語はあなたの決定に影響しますか? パフォーマンス?プログラムのサイズ?個人的なスタイル?

(それも関係ありますか?)

**(宿題: 見つけてください。ただし、偏見を持たないように、自分の答えを探す前に、ここに答えを投稿してください。)*

4

6 に答える 6

16

メソッドは、その関数を実行するために必要な最も具体的でない型を常に受け​​入れる必要があります。メソッドが列挙する必要がある場合は、 を受け入れIEnumerableます。IList<>固有のことを行う必要がある場合は、定義により、 を指定する必要がありますIList<>

于 2009-03-05T05:24:33.757 に答える
5

決定に影響を与える唯一のことは、パラメーターの使用方法です。それを反復するだけの場合は、IEnumerable<T>. インデックス付きメンバーにアクセスする場合 (例: var x = list[3])、または何らかの方法でリストを変更する場合 (例: )、またはlist.Add(x)を使用します。ICollection<T>IList<T>

于 2009-03-05T05:24:22.307 に答える
3

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

SO質問のもう1つの最近の例は、File *(またはファイル記述子)の代わりにファイル名を使用するCAPIでした。そこでは、ファイル名によって、渡すことができるものが大幅に制限されていました(ファイル記述子を使用して渡すことができるものはたくさんありますが、ファイル名を持つものは1つだけです)。

キャストを開始する必要がある場合は、高すぎるか、より具体的なタイプを使用する2番目のメソッドを作成する必要があります。

私が考えることができるこれに対する唯一の例外は、速度が絶対に必要であり、仮想メソッド呼び出しの費用をかけたくない場合です。特定のタイプを宣言すると、仮想関数のオーバーヘッドが削除されます(言語/環境/実装によって異なりますが、一般的なステートメントとしては正しいと思われます)。

于 2009-03-05T05:47:00.520 に答える
3

この質問を促したのは私との話し合いだったので、ユーロ・ミチェリはすでに私の答えを知っていますが、ここにあります! :)

Linq to Objects は、この質問に対するすばらしい答えをすでに提供していると思います。可能な限り単純なインターフェイスを一連のアイテムに使用することで、そのシーケンスの実装方法について最大限の柔軟性が得られます。これにより、遅延生成が可能になり、パフォーマンスを犠牲にすることなく (実際の意味ではなく) 生産性が向上します。

時期尚早の抽象化にはコストがかかることは事実ですが、主にそれは新しい抽象化を発見/発明するコストです。しかし、完全に優れたものが既に提供されている場合、それらを利用しないと気が狂うでしょう。それが、ジェネリック コレクション インターフェイスが提供するものです。

アクセスする必要がある場合に備えて、クラス内のすべてのデータを公開する方が「簡単」であると言う人がいます。IList<T>同様に、Euro は、 などのコンテナー(または具象クラスList<T>) への豊富なインターフェイスを使用してから、混乱を後でクリーンアップする方がよいとアドバイスしました。

ただし、アクセスしたくないクラスのデータメンバーを非表示にして、後でそのクラスの実装を簡単に変更できるようにする方が良いと思うので、参照できる最も単純なインターフェイスを使用する必要があります一連のアイテム。シンプルで基本的なものを公開することから始めて、後でそれを「緩める」方が、緩いものから始めてそれに秩序を課すのに苦労するよりも、実際には簡単です。

IEnumerable<T>したがって、シーケンスを表すために行うと仮定します。次に、AddまたはRemoveアイテムが必要な場合 (ただし、インデックスによるルックアップは必要ありません) を使用しますIContainer<T>。これは継承するIEnumerable<T>ため、他のコードと完全に相互運用できます。

このようにして、そのコードがデータに対して何を実行できるかが完全に明確になります (一部のコードをローカルで調べるだけで)。

小さなプログラムは抽象化をあまり必要としません。それは事実です。しかし、成功すると、大きなプログラムになる傾向があります。最初に単純な抽象化を採用すると、これははるかに簡単になります。

于 2009-03-05T09:39:59.430 に答える
0

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

于 2009-03-05T05:26:20.537 に答える
0

ここで同様の C# の質問に回答しました。私の意見では、コレクションの場合、通常は IEnumerable Of T.

実装は、必要なメンバーが型によって公開されている内部 BCL 型 (Set、Collection、List など) によって提供できます。

抽象型は、具象型によって実装される単純な BCL 型を常に継承できます。私の意見では、これにより、LSPをより簡単に順守することができます。

于 2009-03-05T09:21:20.740 に答える