2012-04-16 5 views
5

可能性の重複:
Collection<T> versus List<T> what should you use on your interfaces?内部リスト<T>をIEnumerable <T>またはICollection <T>として返すことができますか?

この方法-返される変数myVar考えてみてはList<T>ですが、方法MyMethod()の戻り値の型がIEnumerable<T>です:

public IEnumerable<T> MyMethod(string stuff) 
{ 
    var myVar = new List<T>(); 
    //do stuff 

    return myVar; 
} 

本質的に、私が知りたいのは、もしreturni異なるタイプのmyVarはOKです。

具体的には、私の状況に関して、「do stuff」はDataRowを通過し、その中の項目にオブジェクトのリストを割り当てます(DataRow)。私はまた、他の場所でICollectionIListの戻り値の型を持つ同様の状況を持っています。

私がIEnumerableまたはICollectionのいずれかを返す理由は、私が必要以上に戻ってこないようにするためです。しかし同時に、これにより、呼び出し側は返された値をListに変換する必要がある場合にその値を変換することができます。

しかし、私のreturnステートメントは、メソッドの戻り値の型ではなく、Listを返しています。これは通常の練習ですか?これに何か問題はありますか? (だまされやすい人のコメントに応答して)

明確化:

だけ明確にする、体内で私のreturn文がList<T>が、メソッドを返すこと大丈夫であれば、私は好奇心だことはありますヘッダーの戻りタイプがIEnumerable、またはおそらくICollectionCollectionなどです。何かが異なるボディリターンステートメントとは異なります。

+2

呼び出し元は、IEnumerableからListに変換しないでください。インタフェースを返す理由は、根本的なリスト、オーバーバブルコレクション、単純な配列、または利回りリターンによるリストさえあれば問題ではないからです。 – aqwert

+1

2つの提案されたdupesは、この質問よりもそれぞれのdupesに近いです、と私は思っていますが、それらはすべて密接に関連しています。 –

+0

@ChrisCharabaruk私は、この質問は重複していないことに同意し、私はそれがユニークになると信じていることをうまく伝えるためにそれを改作しました。私はまた、質問を再開することに投票しました。 – DavidRR

答えて

6

これには何も問題はないだけでなく、実際には良い練習です。厳密に必要なものだけを公開してください。そうすれば、呼び出し元はメソッドがList<T>を返すという事実に頼ることはできません。何らかの理由で実装を変更して別のものを返す必要がある場合は、契約を解除しません。しかし、実際に何が返されるかについて(間違って)仮定した場合、呼び出しコードになる可能性があります。

+0

"....これが必要な場合は、呼び出し元がリストに変換することができます。 –

+0

@TimSchmelter、もし、呼び出し元が*メソッドがListを返すことを知っていれば、戻り値の型はListでなければなりません。もちろん、これは良い事実でも、常識の問題ではありません;) –

+0

それで、私のreturnステートメントはリストを返しますが、メソッドの戻り値の型はIEnumerable です。これは大丈夫ですか? – RJP

2

何も問題ありません。

具体的にクラスを返すのは、 "return interface"の要件を満たす唯一の方法です。

特定のクラスの知識を呼び出しコード(List<T> r = (List<T>)MyMethod("ff"))に侵入させると、欠点が生じる可能性があります。しかし、結果をインターフェースとして扱うなら(あなたが想定したように)、それは大丈夫です。

3

IEnumerable<T>型を返す理由は、呼び出し元が(リストに戻さずに)リストを変更できないようにするためです。すべて(ほとんどの?)に気づいたら、拡張メソッドはIEnumerable<T>引数を取るので、拡張メソッドでリストが変更されないことがわかります。

第2に、List<T>IEnumerable<T>から継承されます。

編集: トーマスはIEnumerable<T>List<T>に戻ってキャストし、呼び出し側で変更することができることをコメントで説明したように。主な目的が読み取り専用にする場合は、リストをmyVar.AsReadOnly()として返すことができます。しかし、タイプはReadOnlyCollection<T>です。

+0

変更の防止が主な理由であるかどうかわからない – zerkms

+1

呼び出し元がリストを変更できないようにします。呼び出しコードは結果をリストにキャストできます。しかし、そうすることは、実装についての文書化されていない仮定を行うことを意味します。したがって、実装が変更されると破損する可能性があります。 –

+0

'ReadOnlyCollection 'を返すと、返された値の配列意味が保持されます。つまり、アイテムはその整数インデックスで取り出すことができます。コレクションを繰り返し処理することなく、コレクション内のアイテムの数を確認できます。 – DavidRR

1

これは、呼び出し側が実装の詳細に依存するList<T>にキャストできるため、最適ではないと思います。私はSelect(x=>x)のようなマスキングを追加したいと思います。

動的に型指定された呼び出し元は、リストをIEnumerable<T>にキャストすることさえ気づかないかもしれません。彼のためにはそれは単にList<T>です。

List<T>IEnumerable<T>として返すことは、呼び出し元がクラスの内部状態を変更できるため、非常に間違っています。しかし、すべての呼び出しでList<T>の新しいインスタンスを返すので、他の場所では使用されません。この引数は、あなたの例には当てはまりません。

+0

このようにしたい場合は、イテレータを使用することもできます; –

+0

リストをラップすると、無駄なランタイムの手荷物が追加されます。しかし、おそらく100回中に 'List 'を99回返すことができ、たまにラッパーしか返さないのでしょうか?それは 'List'にキャストされたコードを壊しますが、パフォーマンスをあまりに悪くすることはありません。 – supercat

+0

@supercat 99%のコードではこの小さなオーバーヘッドは問題ではないので、私のプロファイリングが重要であることが示されていれば、私は心配していました。 – CodesInChaos

関連する問題