Интереса ради начал изучать внутреннее устройство foreach.
Наткнулся на такой паттерн, который создан, чтобы была совместимость из старого кода:
class Test : IEnumerable<T>
{
public IEnumerable<T> GetEnumerator()
{
}
IEnumerator IEnumerable.GetEnumerator()
{
}
}
Так как мы реализуем generic интерфейс, то должны реализовать и методы из IEnumerable, так как generic интерфейс наследует его.
Как я понял, при написании обычного foreach в текущих версиях языка, будет вызван неявный метод (который первый), исходя из понятия утиной типизации.
Вопрос: почему в старых версиях языка (до generic'ов) будет вызван метод с явной реализацией?
Возможно, там такая реализация (с привидением к non-generic интерфейсу)?
IEnumerator enumerator = ((IEnumerable)TestInstance).GetEnumerator();
...
Или я что-то неправильно понимаю?
Вы задаёте вопрос о C# 1.x, поскольку начиная с версии 2.0 C# уже содержит обобщения.
Посмотрим на спецификацию C# 1.0. Нас интересует раздел 8.8.4 The foreach statement. Согласно этому разделу, используется следующая последовательность проверок:
GetEnumerator, возвращающий объект, обладающий методом MoveNext и свойством Current), то используется этот паттерн (даже если интерфейс IEnumerable тоже поддерживается).IEnumerable, то он используется.В вашем случае, когда метод IEnumerable.GetEnumerator() объявлен через явную имплементацию интерфейса, первое условие не выполняется: метод IEnumerable.GetEnumerator не публичный. (А метода public IEnumerable<T> GetEnumerator() вовсе нет, раз наша версия языка не поддерживает обобщения.) Поэтому работает второе условие.
Кстати, в современных версиях языка просто перед второй проверкой выполняется дополнительная проверка на обобщённый IEnumerable<T>. Но на первом месте в любом случае «утиная» проверка.
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости