31

私が取り組んでいる多くのプロジェクトでは、読み取り専用のコレクションを返す必要があるときはいつでも、IEnumerable<T>インターフェイスを使用して、次のようにタイプ固有にします。

Public ReadOnly Property GetValues() As IEnumerable(Of Integer)
    Get
        'code to return the values'
    End Get
End Property

ほとんどの場合、私はリストを返しますが、一部の関数と読み取り専用プロパティでは、拡張メソッドのおかげで目的を果たしてくれる配列を返します。

私の質問は特定のタイプ(例:、、、またはs)の代わりにsを返すことによって、設計原則に違反しているIEnumerable<T>List<T>HashSet<T>Stack<T>Arrayのでしょうか?

4

8 に答える 8

36

私も一般的に好きIEnumerable<T>です。主なことは、実際の(最小限の)機能がメソッドから返される(またはメソッド引数の場合はメソッドに渡される)ことを自問することです。

結果セットを列挙するだけでよい場合は、IEnumerable<T>まさにそれを実行します。これ以上でもそれ以下でもありません。これにより、メソッドのフットプリントを壊すことなく、必要に応じて特定の場合に、より具体的なタイプを返す柔軟性が得られます。

于 2011-03-01T15:35:37.177 に答える
18

デビッドの答えはほとんどそれをカバーしています。IEnumerable<T>一般的にはベストプラクティスです。これは、ほとんどの新しいフレームワークメソッドを見るとわかります。

これを追加したかったのですが、元の質問で読み取り専用コレクションを指定したので、インスタンスを返す前にインスタンスを呼び出すことでこれを強制でき.ToList().AsReadOnly()ますIEnumerable<T>。これにより、戻るための具体的なインスタンスが作成さReadOnlyCollection<T>れます。発信者は、あなたが具体的に返品していることを知る必要がないため、返品タイプは引き続きである必要がありますが、このようにして、発信者が自分の足を撃つことを防ぎます。IEnumerable<T>ReadOnlyCollection<T>

IEnumerable<T>(この手順がないと、呼び出し元は、たとえば、メソッドから取得したものをにキャストしようとする可能性がありますList<T>。キャストが成功した場合、それが最初に操作していたものである場合、呼び出し元は、内部で操作しているのと同じリストを変更できます。あなたの方法、おそらく予期せぬ結果を伴う。)

于 2011-03-01T15:40:26.307 に答える
16

個人的にIEnumerable<T>は、APIから戻ることは、実装が遅延評価を使用する可能性があることを強く示唆していると思います。

遅延評価を使用できることを知ることは、次のことを意味するため、発信者にとって重要な場合があります。

  • 結果を複数回繰り返すと(たとえば、カウントを取得してからデータにアクセスするため)、評価が複数回実行されます。

  • 結果を反復処理しているときに、APIから例外をスローできます。

例えば

IEnumerable<MyObject> LazyEvaluatedApi()
{
}

...

IEnumerable<MyObject> result = LazyEvaluatedApi();
... 
foreach(MyObject item in result) // Exception from LazyEvaluatedApi may be thrown here.
{
}

実装で遅延評価(データアクセス層APIなど)を使用する必要がないと思われる場合は、ICollection<T>またはを返すことをお勧めしますIList<T>Count呼び出し元にプロパティ(ICollection<T>およびIList<T>)とインデクサー(のみ)へのアクセスを許可する以外に、IList<T>遅延評価がないことも明確に示しています。

ICollection<T>またはを返す場合IList<T>、具体的な実装は通常、を返しますList<T>。リストが読み取り専用であることが重要な場合は、List<T>.AsReadOnly()

于 2011-03-01T17:10:57.347 に答える
3

それはあなたが何をしたいのか、そしてあなたが「違反」しようとしているのかによります。これは以下に依存します:

  1. オブジェクトによって返されるコレクションを外部コードによって変更できるようにする場合は、変更可能なタイプ、別名List <>、HashSet <> Stack <>、または変更を許可するその他のタイプを返す必要があります。
  2. 「コレクションユーザー」がコレクションアイテムを反復処理するだけで、コレクション自体を変更しないようにする場合は、これが正しい選択です。

多くの優れた設計の達人と原則は、modizable-collection-readyよりもIEnumerable<>を返すことを好むことを覚えておいてください。

于 2011-03-01T15:39:51.470 に答える
2

返却IEnumerable<T>は大丈夫です。Tが参照型の場合、呼び出し元がオブジェクトを変更する可能性があることに注意してください。

必要な最小限の機能を提供する最も一般的なタイプを返す必要があります。この場合、呼び出し元がデータを処理する必要があるだけの場合は、IEnumerableが他のコレクションタイプよりも適切List<T>ですHashSet<T>。このようにして、呼び出し元はメソッドの実装から切り離されたままになり、呼び出し元を中断することなく、将来的にメソッドの実装を自由に変更できます。

于 2011-03-01T15:37:52.670 に答える
0

List<T>、などによって提供される追加機能が必要ない場合は、HashSet<T>を返すことIEnumerable<T>で問題ありません、imo。

最も適切と思われるタイプを返します。コレクションをループするか、コレクションでLINQ-yを実行するだけでよい場合IEnumerable<T>は、ほとんどの状況で適しています。

「よりリッチな」型を返す必要がある場合は、呼び出し元のコードを壊すことなく、必要に応じて実装を将来変更できるように、具体的な型ではなく、などIList<T>List<T>ISet<T>なく、インターフェイスを返すことを検討してください。HashSet<T>

于 2011-03-01T15:34:23.673 に答える
0

場合によります。メソッドの使用が単なる列挙である場合は、IEnumerableが正しい選択です。

インデックスルックアップなどの特定の機能が重要な場合は、より具体的にすることができます。

とはいえ、いつでもIEnumerableをLINQ式でラップして、何でも使用できます。返された型がLINQ式で使用される機能をすでにサポートしている場合は、巧妙なコンパイラがその式を最適化できます。

于 2011-03-01T15:37:55.387 に答える
0

IEnumerableは、クエリロジックを組み合わせることができるため、クエリが高速です。コレクションに影響を与えている間はコレクションを変更したくないので、通常は配列を使用して値を削除または変更します。

于 2011-03-01T15:53:01.643 に答える