2009-09-21 3 views
4

Надеюсь, я не захлопнувшись за то, что вы задали что-то такое основное. Я мог ответить Google, но я хочу услышать что-то, что не из учебника.Перечислите набор IDictionary.Keys, который является ICollection <T>

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

Поскольку свойство Keys является ICollection<T>, я хочу перечислить коллекцию и распечатать значения ключа на консоли.

При попытке печати значений ключа с помощью простого for цикла:

for (int i = 0; i < unPivotedData.Count; i++) 
{ 
    Console.WriteLine(unPivotedData.Keys[i]); 
} 

я получил следующую компиляции ошибка:

Cannot apply indexing with [] to an expression of type 'System.Collections.Generic.ICollection<int>' 

Однако, когда я использовал foreach цикл:

foreach(int key in unPivotedData.Keys) 
{ 
    Console.WriteLine(key); 
} 

Все работало нормально.

Я понимаю, что делает индексатор и как оно реализовано, но как работает foreach? Я не понимаю, как может работать foreach, но for приводит к ошибке компилятора.

Я пропустил фундаментальное перечисление здесь?

Cheers!

EDIT: Кроме того, есть ли разница в производительности между двумя? Я знаю, что не могу использовать for с IDictionary, но если я использую IList, я могу. Имеет ли for двигаться быстрее, чем foreach или прирост производительности незначителен

ответ

8

foreach просто необходимо IEnumerable; тогда как for(a,b,c) (в вашем случае) требует свойства индексатора.

При вызове foreach на объекте, который реализует IEnumerable под капотом она вызывает GetEnumerator(), который возвращает объект IEnumerator. Этот объект реализует несколько членов, таких как MoveNext() и Current. Каждая итерация foreach на самом деле вызывает MoveNext(), который возвращает true, если перечислитель может двигаться вперед, а false, если он не может (дошел до конца).

Ключ здесь в том, что объект, который реализует IEnumerable, не знает, сколько у него предметов, индекса элемента, на котором он установлен, и т. Д. Все, что он знает, это то, что он может перейти к следующему элементу, вернуть это как текущий элемент, пока он не закончится.

A for(a,b,c) петля, с другой стороны, будет по существу петлей навсегда - то есть она не ограничена коллекцией, в которой вы, возможно, будете итерировать (хотя на практике это обычно есть). На самом базовом уровне он выполняет один раз C и проверяет, действительно ли B. Если значение B истинно, оно снова запустится. Если он ложный, он остановится.Каждый раз, когда он зацикливается, внутри цикла вы, вероятно, вызываете object[number], который, если у вашего объекта нет такого свойства, будет, конечно, терпеть неудачу.

Ключевым моментом здесь является то, что объект с индексатор поддерживает произвольного доступа - это означает, что вы можете в любой момент позвонить [arbitrary index] и захватить тот. Контрастируйте это с помощью IEnumerable, который снова может получить доступ только к текущей позиции.

1

Foreach использует интерфейс IEnumerable. Посмотрите, как это определение поможет, и вы получите представление.

0

Предпросмотр проходит через интерфейс IEnumerable, который просто предоставляет пользовательский Enumerator. См. http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx для информации.

В основном, он действует как обычная вещь со связанными списками, с «текущим» и «движением дальше».

1

Как уже заявил Еогеасп использует Enumerator коллекции, так

foreach(int key in unPivotedData.Keys) 
{ 
    Console.WriteLine(key); 
} 

перевести что-то вроде:

IEnumerator enumerator = unPivotedData.Keys.GetEnumerator() 
while(enumerator.MoveNext()) 
{ 
    Console.WriteLine(enumerator.Current); 
} 

, как вы можете видеть, что нет индексации в этом. Индексация - это совсем другое зверь из итератора, который может использоваться для целей итерации (как вы пытаетесь в этом для цикла), но итератор не может использоваться для индексирования только итерации

4

Коллекция ключей не индексируется, поскольку по определению словарь, упорядочение элементов не гарантируется. Который, к сожалению, также означает, что цель единичного теста, который вы пишете, в корне неверна.

3

Вы можете думать о различии между IList<T> (который поддерживает индексирование) и IEnumerable<T> так:

Если у меня есть комната с объектов, разбросанных по всему полу, и я прошу вас, чтобы получить для меня все объекты в комнате, вы можете просто войти, начать собирать предметы в определенном порядке и бросать их мне. Заказ не имеет значения; Важно то, что вы проходите все предметы. Объекты в комнате, в этом смысле, могут быть абстрактно рассмотрены как реализация интерфейса IEnumerable. Тогда, если я брошу все предметы обратно в комнату и попрошу вас сделать это снова, когда вы пройдете через них во второй раз нет гарантии, что вы заберете их в том же порядке. По сути, это потому, что нет смысла спрашивать: «Что такое n-й пункт в комнате?»

Это важное замечание о IEnumerable: хотя я никогда не видел случай, когда foreach не использует тот же порядок, при каждом вызове, он не имеют к.

С другой стороны, если я помещаю предметы в комнату в определенном порядке, и я прошу вас зайти и забрать их в том же порядке, в котором я разместил их, тогда было бы целесообразно назначить число для каждого объекта. Вопрос: «Что такое номер, который я разместил в комнате?» на самом деле имеет смысл в этом контексте. Таким образом, в этом случае объекты в помещении могут рассматриваться как реализация интерфейса IList.