При написании кода на языке C# достаточно часто приходится использовать конструкцию foreach. Ведь так на много удобнее проходить по коллекциям, по сравнению с использованием цикла for. Безусловно, у каждого метода есть свои плюсы и минусы и выбор всегда зависит от конкретной задачи и ситуации. Но на днях меня удивила одни интересная особенность конструкции foreach, а именно то, как это работает.
Рассмотрим простой пример:
У нас есть некая коллекция элементов и с помощью **foreach **мы выводим на консоль имена всех элементов.
При этом класс **MyCollection **выглядит так:
Класс коллекции реализовывает единственный метод **GetEnumerator **интерфейса ** IEnumerable **для возможности использования класса в конструкции foreach.
Особенности enumerator’а нас сейчас не интересуют, будем считать что он работает так, как ему положено.
Теперь сделаем простую вещь, а именно, поменяем наш класс **MyCollection **так, чтобы он больше не реализовывал интерфейс IEnumerable, при этом метод GetEnumerator оставим без изменений.
К моему удивлению, код и дальше продолжил компиляцию и правильно работал. Первым делом, посмотрим какой IL-код у нас получился:
Тут хорошо видно, что при создании IL-кода компилятор не обращает внимания на наличие интерфейса IEnumerable, а непосредственно вызывает метод ** GetEnumerator**. На этом моменте мне стало интересно и я пошел читать спецификацию языка C# (Standard ECMA-334 C# Language Specification), которая, к слову, датирована далёким июнем 2006-го года. В разделе 8.18 Итераторы сказано следующее:
The foreach statement is used to iterate over the elements of an enumerable collection. In order to be enumerable, a collection shall have a parameterless GetEnumerator method that returns an enumerator. Generally, enumerators are difficult to implement, but the task is significantly simplified with iterators.
Таким образом, получается что для использования коллекции в конструкции ** foreach **достаточно только метода GetEnumerator, а наличие интерфейса - необязательное условие.Пример кода доступен по адресу: https://github.com/e0ne/BlogSamples/tree/master/ForeachTest