web-dev-qa-db-ja.com

[System.Collections.Generic.IEnumerable <>型の式に[]を使用したインデックス付けを適用できません

IEnumerableでインデックス作成が許可されない特定の理由はありますか。

私が抱えていた問題の回避策を見つけましたが、なぜ索引付けが許可されないのかを知りたいだけです。

おかげで、

58
Sandeep

そうではないからです。

インデックス作成はIListでカバーされます。 IEnumerableは、「IListのパワーの一部を持っていますが、すべてではありません」という意味です。

一部のコレクション(リンクリストなど)は、実用的な方法でインデックスを作成できません。ただし、アイテムごとにアクセスできます。 IEnumerableは、そのようなコレクションを対象としています。コレクションは、IListとIEnumerable(および他の多く)の両方を実装できることに注意してください。通常、IEnumerableは関数パラメーターとしてのみ検索されます。つまり、必要なのは最も単純なアクセスモードだけなので、関数はあらゆる種類のコレクションを受け入れることができます。

65
James Curran

_IEnumerable<T>_ インターフェースには indexer が含まれていません。おそらく _IList<T>_ と混同しているでしょう

オブジェクトが実際に_IList<T>_(例えば_List<T>_または配列_T[]_)である場合、タイプ_IList<T>_の参照も作成してみてください。

それ以外の場合は、 Enumerable.ElementAt 拡張メソッドを使用するmyEnumerable.ElementAt(index)を使用できます。これはすべての_IEnumerable<T>_ sで機能するはずです。 (ランタイム)オブジェクトが_IList<T>_を実装しない限り、これにより最初の_index + 1_アイテムがすべて列挙され、最後のアイテム以外はすべて破棄されることに注意してください。

編集:説明として、_IEnumerable<T>_は単に「列挙子を公開するもの」を表すインターフェースです。具体的な実装は、doesがインデックスによる高速アクセスを許可する、または許可しないメモリ内リストのようなものです。たとえば、リンクリスト(James Curranによる言及)など、このようなクエリを効率的に満たすことができないコレクションである可能性があります。それは、no-sortであり、イテレータなど、要求に応じて項目が生成される(「yielded」)メモリ内データ構造である場合もあります。 、またはリモートデータソースからアイテムを取得する列挙子によって。 _IEnumerable<T>_はこれらすべてのケースをサポートする必要があるため、インデクサーはその定義から除外されます。

44
Ani

列挙型が次のような文字列の場合、インデックスを使用できます

((string[])MyEnumerableStringList)[0]
3
Code_Worm

理由の1つは、IEnumerableに不明な数のアイテムが含まれている可能性があることです。実装によっては、アイテムのリストを反復処理して作成します(サンプルについては yield を参照)。インデックスを使用してアイテムにアクセスする場合、これはあまりうまくいきません。リストには少なくともその数のアイテムがあることを知る必要があります。

3
Fredrik Mörk

[] -operatorは、Element -Collectionに依存する実装で、アクセスプロパティthis[sometype index]に解決されます。

Enumerable-Interfaceは、最初にブループリントを宣言します[コレクションがどのように見えるべきか]。

クリーンなインターフェイス分離の有用性を示すために、この例を取り上げます。

var ienu = "13;37".Split(';').Select(int.Parse);
//provides an WhereSelectArrayIterator
var inta = "13;37".Split(';').Select(int.Parse).ToArray()[0];
//>13
//inta.GetType(): System.Int32

[]-operatorの構文も見てください:

  //example
public class SomeCollection{
public SomeCollection(){}

 private bool[] bools;

  public bool this[int index] {
     get {
        if ( index < 0 || index >= bools.Length ){
           //... Out of range index Exception
        }
        return bools[index];
     }
     set {
        bools[index] = value;
     }
  }
//...
}
2
Lorenz Lo Sauer

ToListを使用してリストに変換できます。例えば、

SomeItems.ToList()[1]
2
Donal

インターフェイスの概念は、一般に、オブジェクトで作業を実行するコードがそのオブジェクトによって提供される特定の機能を保証できる一種のベースラインコントラクトを公開することです。 IEnumerable<T>の場合、その契約はたまたま「すべての要素に1つずつアクセスできます」です。

この契約だけに基づいて記述できるメソッドの種類は多数あります。例のtonsについては Enumerable クラスを参照してください。

しかし、具体的な1つだけに焦点を当てるには、 Sum について考えます。たくさんのアイテムをまとめるには、何が必要ですか?どのような契約が必要ですか?答えは非常に簡単です。すべてのアイテムを表示する方法であり、これ以上はありません。ランダムアクセスは必要ありません。すべてのアイテムの総数でさえ必要ではありません。

インデクサーをIEnumerable<T>インターフェイスに追加すると、2つの方法で有害になります。

  1. 上記のコントラクト(要素のシーケンスへのアクセス)を必要とするコードは、IEnumerable<T>インターフェイスが必要な場合、インデクサーを実装していなくてもインデクサーを実装していない型を処理できないため、人為的に制限されますそのようなタイプでは、コードの機能の範囲内に収まるはずです。
  2. 要素のシーケンスを公開したいが、インデックスによるランダムアクセスを提供するのに適切に装備されていないタイプ(たとえば、LinkedList<T>Dictionary<TKey, TValue>)は、シミュレーションインデックス作成、またはIEnumerable<T>インターフェイスを放棄します。

これはすべて、インターフェイスの目的は、特定のシナリオで最低限必要な機能の保証を提供することであることを考えると、IList<T>インターフェイスは本当に設計が不十分です。むしろ、 ""の間のインターフェース "IEnumerable<T>IList<T> (ランダムアクセス、ただし変更なし)の欠如は、BCLの不幸な見落としです。

1
Dan Tao