static void Main(string[] args)
{
List<int> listArray = new List<int>();
listArray.Add(100);
foreach (int item in listArray)
Console.WriteLine(item);
}
a) Когда оператор foreach
вызывает реализацию listArray IEnumerable<int>.GetEnumerator()
, вызывает ли он его через listArray.GetEnumerator()
или IEnumerable<int>.GetEnumerator()
или IEnumerable.GetEnumerator()
?
b) Точно так же, когда foreach
ссылается на объект, возвращаемый listArray IEnumerable<int>.GetEnumerator()
, ссылается ли этот объект на него через IEnumerator
или IEnumerator<int>
тип ссылки?
Благодарю вас
EDIT:
Некоторые из моих вопросов цитируют этот текст:
o Выполнить поиск элемента по типу X с идентификатором GetEnumerator и no типа. Если поиск элемента не дает соответствия, или вызывает двусмысленность или создает совпадение, которое не является группой методов, проверить перечислимый интерфейс как описано ниже. Рекомендуется что предупреждение выдается, если член поиск производит что-либо, кроме группа методов или отсутствие соответствия.
o Выполните разрешение перегрузки, используя результирующая группа методов и пустой список аргументов. Если перегрузка результаты разрешения не применимы методов, приводит к двусмысленности или приводит к одному наилучшему методу, но этот метод является либо статическим, либо не публичный, проверить перечислимый интерфейс, как описано ниже. это рекомендовал выпустить предупреждение если возникает перегрузка ничего, кроме недвусмысленной публики метод экземпляра или не применяется Методы.
o Если тип возврата E Метод GetEnumerator не является классом, структуры или типа интерфейса, ошибка и дальнейшие шаги приняты.
o Поиск члена выполняется на E с идентификатором Current и no типа. Если поиск элемента не дает совпадения, результатом является ошибка, или результат - что угодно кроме свойства публичного экземпляра, которое разрешает чтение, возникает ошибка и никаких дальнейших шагов не предпринимается.
o Поиск члена выполняется на E с идентификатор MoveNext и тип нет аргументы. Если поиск элемента не дает совпадения, результатом является ошибка, или результат - что угодно кроме группы методов, ошибка и дальнейшие шаги приняты.
o Разрешение перегрузки выполняется группа методов с пустым список аргументов. Если разрешение перегрузки не приводит к каким-либо применимым методам, приводит к двусмысленности или приводит к единственный лучший метод, но этот метод является либо статическим, либо не публичным, либо его тип возврата не является bool, ошибка и дальнейшие шаги приняты.
o Тип коллекции - X, тип перечислителя - E, а элемент тип - тип тока имущество.
В противном случае проверьте перечислимый интерфейс: o Если существует ровно один тип T такой, что существует неявный преобразование из X в интерфейс System.Collections.Generic.IEnumerable, то тип коллекции - это интерфейса, тип перечислителя является интерфейс System.Collections.Generic.IEnumerator, и тип элемента - T.
В противном случае, если существует более одного такого типа T, то ошибка и дальнейшие шаги.
В противном случае, если есть неявное преобразование из X в System.Collections.IEnumerable интерфейса, тогда тип коллекции этот интерфейс, тип перечислителя интерфейс System.Collections.IEnumerator и тип элемента - это объект.
В противном случае возникает ошибка, и дальнейшие шаги не выполняются приняты.
1)
Цитата из Эрика Липперта:
Опция (1) верна. Обратите внимание, что это означает, что возвращаемый счетчик unboxed mutable struct.
Тот факт, что это изменяемая структура имеет очень реальные последствия, если вы это сделаете что-то глупое, как обход структура, как если бы это была ссылочный тип; он будет скопирован значение, а не по ссылке.
Из http://en.csharp-online.net/ECMA-334:_15.8.4_The_foreach_statement:
foreach (V v in x) embedded-statement
затем расширяется до:
{ E e = ((C)(x)).GetEnumerator(); try { V v; while (e.MoveNext()) { v = (V)(T)e.Current; embedded-statement } } finally { … // Dispose e } }
Переменная e не видна или доступный для выражения x или встроенный оператор или любой другой источник код программы.
В случае listArray
возвращаемый перечислитель сохраняется (т.е. его значение сохраняется) в переменной e
(таким образом, переменная e
является изменяемой структурой). Но в соответствии с вышеприведенной выдержкой e
не доступный для моего исходного кода, так как я мог бы передать эту структуру вокруг (если я не пишу код, который делает вручную то, что оператор foreach
делает автоматически)?
2)
Поиск элемента выполняется на E с идентификаторами Current и no type. Если поиск элемента не приводит к совпадению, результатом является ошибка, или результат - это что-то за исключением свойства публичного экземпляра, которое разрешает чтение, возникает ошибка и нет предпринимаются дальнейшие шаги.
Кажется, что если мы реализуем GetEnumerator
в самом классе (X
), то Current
также должен быть реализован в самом классе (e
) (таким образом, e
не должен явно реализовывать Current
), поскольку компилятор не потрудится проверять интерфейсы IEnumerator<T> / IEnumerator
в случаях, когда поиск элемента (в e
с идентификатором Current
) не дает соответствия?
3)
Если существует ровно один тип T такой, что существует неявное преобразование из X в интерфейс System.Collections.Generic.IEnumerable, то тип коллекции - это интерфейс, тип перечислителя - это интерфейс System.Collections.Generic.IEnumerator, а тип элемента - T.
В соответствии с вышеизложенным, если foreach
должен проверить интерфейс IEnumerable<T>
, то foreach
всегда будет использовать IEnumerator<T>
версию Current
? Таким образом, если e
явно реализует IEnumerator<T>
версию Current
, и если она также реализует другую версию Current
в самом классе, foreach
всегда будет вызывать IEnumerable<T>
версию Current
?
4)
Метод GetEnumerator документируется как возвращающий один из них:
Что вы подразумеваете под одним из них (как во множественном числе)? Вы указали, что GetEnumerator
(как реализовано List<T>
) возвращает только struct
.
5)
г. Тип коллекции - X, тип перечислителя - E, а тип элемента - тип свойства Current
Возможно, бесполезный вопрос - согласно выше, foreach
не проверяет, какие типы элементов хранит определенная пользователем коллекция, но вместо этого предполагает, что тип элементов совпадает с типом, возвращаемым Current
имущество?