Подтвердить что ты не робот

Невозможно применить индексирование с [] к выражению типа "System.Collections.Generic.IEnumerable <>

Есть ли какая-либо конкретная причина, по которой индексирование не разрешено в IEnumerable.

Я нашел обходной путь для проблемы, которую я имел, но просто любопытно узнать, почему это не позволяет индексировать.

Спасибо,

4b9b3361

Ответ 1

Потому что это не так.

Индексирование распространяется на IList. IEnumerable означает "у меня есть некоторые полномочия IList, но не все из них".

Некоторые коллекции (например, связанный список) не могут быть проиндексированы на практике. Но они могут быть доступны по каждому элементу. IEnumerable предназначен для подобных коллекций. Обратите внимание, что коллекция может реализовывать как IList, так и IEnumerable (и многие другие). Обычно вы находите IEnumerable как параметр функции, то есть функция может принимать любые коллекции, потому что все, что ему нужно, - это самый простой режим доступа.

Ответ 2

Интерфейс IEnumerable<T> не включает indexer, вы, вероятно, путаете его с IList<T>

Если объект действительно является IList<T> (например, List<T> или массив T[]), попробуйте сделать ссылку на него типа IList<T> тоже.

В противном случае вы можете использовать myEnumerable.ElementAt(index), который использует метод расширения Enumerable.ElementAt. Это должно работать для всех IEnumerable<T>. Обратите внимание, что если объект (run-time) реализует IList<T>, это приведет к перечислению всех первых элементов index + 1, при этом все, кроме последнего, будут отброшены.

EDIT: В качестве объяснения, IEnumerable<T> - это просто интерфейс, который представляет "то, что предоставляет перечислитель". Конкретная реализация вполне может быть своего рода списком в памяти, который позволяет быстро получить доступ по индексу, а может и нет. Например, это может быть сборник, который не может эффективно удовлетворять такой запрос, например, связанный список (как упоминал Джеймс Карран). Это может быть вообще не какая-либо структура данных в памяти, например, итератор, где элементы генерируются ( "даны" ) по требованию или перечислителем, который извлекает элементы из какого-то удаленного источника данных. Поскольку IEnumerable<T> должен поддерживать все эти случаи, индексаторы исключаются из его определения.

Ответ 3

Одна из причин может заключаться в том, что IEnumerable может содержать неизвестное количество элементов. В некоторых реализациях создается список элементов по мере его перебора (см. yield для образцов). Это не очень хорошо работает с доступом к элементам с использованием индекса. что потребует от вас знать, что в списке есть по крайней мере много элементов.

Ответ 4

вы можете использовать индексирование, если ваш перечислимый тип является строкой, как показано ниже

((string[])MyEnumerableStringList)[0]

Ответ 5

[] -оператор разрешен к свойству доступа this[sometype index], с реализацией в зависимости от коллекции элементов.

Перечислимый интерфейс объявляет план того, что коллекция должна выглядеть в первую очередь.

Возьмите этот пример, чтобы продемонстрировать полезность чистого разделения интерфейса:

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

Также посмотрите на синтаксис для [] -оператора:

  //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;
     }
  }
//...
}

Ответ 6

Идея интерфейсов, как правило, заключается в том, чтобы разоблачить какой-то контракт базовой линии, посредством которого код, который выполняет работу над объектом, может быть гарантирован определенной функциональностью, предоставляемой этим объектом. В случае IEnumerable<T>, этот контракт оказывается "вы можете получить доступ ко всем моим элементам один за другим".

Типы методов, которые могут быть написаны на основе этого договора, очень много. См. Enumerable для тонн примеров.

Но к нулю только один конкретный: подумайте о Sum. Чтобы суммировать кучу предметов, что вам нужно? Какой контракт вам нужен? Ответ довольно прост: просто способ увидеть каждый предмет, не более того. Случайный доступ не требуется. Даже общее количество всех предметов не требуется.

Добавление индексатора в интерфейс IEnumerable<T> было бы пагубно двумя способами:

  • Код, требующий описанного выше контракта (доступ к последовательности элементов), если он требует интерфейса IEnumerable<T>, был бы искусственно ограничительным, поскольку он не мог иметь дело с любым типом, который не реализовал индексатор, хотя для сделка с таким типом должна действительно хорошо соответствовать возможностям кода.
  • Любой тип, который хотел бы выставить последовательность элементов, но не был надлежащим образом оборудован для обеспечения произвольного доступа по индексу (например, LinkedList<T>, Dictionary<TKey, TValue>), теперь должен был либо предоставить некоторые неэффективные средства имитации индексации, либо отказаться от интерфейса IEnumerable<T>.

Все это сказано, учитывая, что цель интерфейса - обеспечить гарантию минимально необходимой функциональности в данном сценарии, я действительно думаю, что интерфейс IList<T> плохо разработан. Вернее, отсутствие интерфейса "между" IEnumerable<T> и IList<T> (произвольный доступ, но без изменений) является неудачным наблюдением в BCL, в моем мнение.

Ответ 7

Вы можете использовать ToList для преобразования в список. Например,

SomeItems.ToList()[1]