ほとんどの開発者には、作業する事前評価済みのメモリ内コレクションがあることを意味しますIList
。ICollection
具体的にIList
は、定数時間Add
*とインデックス操作の暗黙の契約があります。LinkedList<T>
これがを実装しないIList<T>
理由です。FibonacciList は、この暗黙の契約に違反していると考えます。
読み取り専用のコレクション インターフェイスを .NET 4.5 に追加する理由について説明している最近の MSDN マガジンの記事の次の段落に注意してください。
IEnumerable<T>
型のコレクションを扱うほとんどのシナリオでは十分ですが、提供される以上の機能が必要になる場合があります。
- マテリアライゼーション:
IEnumerable<T>
コレクションが既に使用可能 (「具体化」) されているかどうか、またはコレクションを反復処理するたびに計算されるかどうか (たとえば、LINQ クエリを表す場合) を表現することはできません。アルゴリズムがコレクションに対して複数の反復を必要とする場合、シーケンスの計算にコストがかかると、パフォーマンスが低下する可能性があります。また、後続のパスでオブジェクトが再度生成されるときに ID の不一致が原因で、微妙なバグが発生する可能性もあります。
他の人が指摘しているように、あなたが何のために返すかという問題もあります.Count
.
これらの型は遅延評価できることが期待されるため、このようなデータのコレクションに対してIEnumerable
orを使用してもまったく問題ありません。IQueryable
編集 1 について:はインターフェイス.Count()
によって実装されていません:拡張メソッドです。そのため、開発者は時間がかかる可能性があることを想定する必要があり、アイテムの数を実際に知る必要がない場合に呼び出さないようにする必要があります。たとえば、 にアイテムがあるかどうかだけを知りたい場合は、 を使用することをお勧めします。処理するアイテムの最大数があることがわかっている場合は、 を使用できます。コレクションに 個以上のアイテムがある場合、IEnumerable<T>
IEnumerable<T>
.Any()
.Take()
int.MaxValue
.Count()
操作オーバーフローが発生します。したがって、無限シーケンスに関連する危険を軽減するのに役立つ回避策がいくつかあります。明らかに、プログラマーがこれらの可能性を考慮していない場合、それでも問題が発生する可能性があります。
編集2について:インデックス作成が一定時間行われるようにシーケンスを実装することを計画している場合、それは私の主なポイントに非常に簡単に対処します。ただし、Sixlettervariables の答えは依然として当てはまります。
*明らかにこれには他にもあります:が返さAdd
れた場合にのみ動作することが期待されます 変更は、戻り値が false などの場合にのみ可能です。そもそも、よく考えられていないインターフェイスでした。この事実は、.NET 4.5 での読み取り専用コレクション インターフェイスの導入によって最終的に改善される可能性があります。IList.IsFixedSize
false
IsReadOnly
IList
アップデート
これを少し考えてみた結果、IEnumerable<>
s も無限であってはならないという個人的な意見に行き着きました。のようなメソッドの実体化に加えて.ToList()
、LINQ にはいくつかの非ストリーミング操作があり、最初の結果を返す前に.OrderBy()
全体を消費する必要があります。IEnumerable<>
非常に多くのメソッドが s を完全にトラバースしても安全であると仮定しているため、無期限にトラバースすることが本質的に安全でない をIEnumerable<>
作成することは、リスコフの置換原則に違反します。IEnumerable<>
アプリケーションでフィボナッチ数列のセグメントを IEnumerables として必要とすることが多い場合は、 のようなシグネチャを持つメソッドを作成することをお勧めしEnumerable.Range(int, int)
ます。これにより、ユーザーは開始インデックスと終了インデックスを定義できます。
Gee-Whiz プロジェクトに着手したい場合は、次のようにIQueryable<>
、ユーザーが LINQ クエリ構文の限定されたサブセットを使用できるフィボナッチ ベースのプロバイダーを開発することが考えられます。
// LINQ to Fibonacci!
var fibQuery = from n in Fibonacci.Numbers // (returns an IQueryable<>)
where n.Index > 5 && n.Value < 20000
select n.Value;
var fibCount = fibQuery.Count();
var fibList = fibQuery.ToList();
クエリ プロバイダーは句をラムダ式として評価する権限を持っているため、メソッドwhere
を実装するのに十分な制御があり、クエリが実際の回答を生成するのに十分な制限があることを確認したり、すぐに例外をスローしたりすることができます。メソッドが呼び出されます。Count
.GetEnumerator()
しかし、これは巧妙であるという悪臭を放ち、実際のソフトウェアにとってはおそらく非常に悪い考えです。