2012-03-31 7 views
4

のパラメータでタイプをにする前に、メソッドのパラメータとしてコレクションを渡した場合、IEnumerable<T>タイプを使用しました。IEnumerableを使用する方法

しかし、最近、私は同様の方法で作成されたタイプIEnumerable<T>の収集に問題が持っていた:私は(例えば、foreachの)コレクションの人々を使用している場合は、常に、この場合

var peoples = names.Select(name => new People(name)); 

を、 Peopleクラスの新しいインスタンスが作成され、簡単にエラーが発生する可能性があります。

IEnumerable <T>タイプパラメータを使用するのが正しいかどうかを質問したいと思います。私はそれが問題を引き起こすかもしれないと思う(上記の例を参照)。このタイプは使用しないでください。どのような選択肢をお勧めしますか(ICollection<T>,など)、どの代替手段を使用するのですか?

または、Selectメソッドでオブジェクトを作成すると愚か者しか使用されないため、これは愚かな疑問だと思いますか?

もちろん、私はToArray()またはToList()を使用して問題を解決できることを知っています。しかし、この方法を使用する他の誰か、それを知ることはできません。私は正しいタイプのパラメータを選択することによってこれを防ぐ方法を知りたいと思います。リストや配列はあまりにも私のために私はちょうどオブジェクトを "列挙"したい特定です。

+1

「新しい人(名前)」を使用してどのようなエラーが発生する可能性がありますか? –

+0

Wiktor Zychla:問題:人々を使用する場合、常にPeopleというクラスの新しいインスタンスが作成されます。 – mveith

答えて

7

IEnumerableはコレクションではありません。あなたが「列挙」することができるものです。問題はIEnumerableをメソッドに渡していないため、LINQ(Selectメソッド)を使用している場合は、列挙型を読み取るたびにコードを再度実行することに問題があります。それでもIEnumerable(またはListを)受け入れて任意のメソッドに渡すことができますし、それが唯一のインスタンスを作成します。このよう

var peoples = names.Select(name => new People(name)).ToList(); 

:あなただけそれが一度だけ実行したい場合は、ToArray()ToList()メソッドを使用することができます一人一人

編集: この方法では、このような問題はありません。それは発信者の問題です。あなたのメソッドをリストの代わりに列挙型で呼び出すことは、完全に良い理由があるかもしれません。呼び出し側は、列挙可能メソッドが別のメソッドに渡すと列挙可能な結果が異なることを知っておく必要があります。そのことについて心配する必要はありません。

唯一の例外は、メソッド自体に複数回パラメータを列挙した場合です。この場合、メソッド内のリストにパラメータをキャッシュして、必要な回数だけリストを列挙する必要があります。

+0

これは完全には正確ではありませんが、LINQは遅延実行を使用していますので、答えを示す列挙可能なものからプルしようとするまで実際には実行されません。しかし、列挙型にアクセスするたびにクエリを再実行することはありません。したがって、foreachのループ式にLINQステートメントを置くことができ、クエリを1回だけ実行します。マイクロソフト社はこれを最適化するのに尽力しました。 – KodeKreachor

+1

はい、ただし、2つのforeach文を使用して列挙型にアクセスすると、ifが2回再評価されます。 – aKzenT

+0

私は2つのforeachステートメントがこの質問に関係していた部分を逃したと思います。申し訳ありませんが、私は意味するようにしようとしていない、ちょうど私達が正確な答えを与えていることを確認したい。 – KodeKreachor

2

ToArrayToListの提案は、最初に考えたことよりも多くを公開しています。このアドバイスは、コールサイトまたはメソッドの最初のものでToList/ToArrayを呼び出すと問題が解決すると言いますが、ご質問はIEnumerable<T>が適切かどうかを尋ねます。パラメータタイプIEnumerable<T>から、List<T>IList<T>およびCollection<T>がすべてそうするように、このインターフェイスを実装するものに変換するために呼び出し元にonusを置く他のもの(ICollection<T>のようなもの)に。このアプローチの問題点の1つは、これらのインターフェイスが変更可能なコレクションを表しているのに対し、IEnumerable<T>はメソッドがアイテムを列挙することを宣言しています。このアプローチが気に入らない理由の1つにすぎません。

潜在的なバグが本当にバグではない場合はどうなりますか?おそらく、呼び出し元はこれらを防御コピーまたはダムデータオブジェクトとしたいと思うかもしれません。後者の場合、いくつかの対策では非効率的かもしれませんが、コピーを作成する必要がありますが、この提案された用途では間違いなくバグではありません。同様に、IEnumerable<T>オブジェクトは必ずしも終了する必要はないので、1つのサイズの推奨値はすべて適合しませんが、配列タイプを渡す必要があると、無限の(すなわち計算された)または単に大きいIEnumerable<T>オブジェクトが出てきます問題の

いずれにせよ、あなたは防衛プログラミングに関する質問をするのは正しいと思います。しかし、この場合、最良の解決策は、IEnumerable<T>に固執し、限られた状況ではバグを導入するかもしれないという推測に基づいて発信者を制限するのではなく、教育することだと思います。引用言い換え

を馬鹿になります問題を防ぐために、設計の問題点は、馬鹿はとても独創的なのろわれていることです。

これが役に立ちます。乾杯!

+0

これはバグではないが、望ましい動作が非常に興味深いという考えは、私には決して起こらなかった。ありがとう、私はこれらの場合にIEnumerable を引き続き使用します。あなたの見積もりは完璧です。 :) – mveith

関連する問題