Прежде всего, чтобы объяснить некоторую предысторию читателям, которые смущены вопросом: язык C # фактически не требует, чтобы коллекция "foreach" реализовывала IEnumerable
. Скорее, требуется либо реализация IEnumerable
, либо реализация IEnumerable<T>
, , либо просто наличие у него метода GetEnumerator (и что метод GetEnumerator возвращает что-то с Current и MoveNext, совпадающим с ожидаемый рисунок и т. д.)
Это может показаться странной функцией для статически типизированного языка, такого как C #. Почему мы должны "соответствовать шаблону"? Почему бы не потребовать , чтобы коллекции реализовывали IEnumerable?
Подумайте о мире перед дженериками. Если вы хотите создать коллекцию целых, вам придется использовать IEnumerable. И, следовательно, каждый вызов Current будет помещать в ячейку int, и, конечно, вызывающий сразу же распаковывает его обратно в int. Что медленно и создает давление на GC. Используя подход, основанный на шаблонах, вы можете создавать строго типизированные коллекции в C # 1.0!
В настоящее время, конечно, никто не реализует этот шаблон; если вы хотите строго типизированную коллекцию, вы реализуете IEnumerable<T>
и все готово. Если бы в C # 1.0 была доступна универсальная система типов, маловероятно, что функция "соответствия шаблону" была бы реализована в первую очередь.
Как вы заметили, вместо поиска шаблона код, сгенерированный для динамической коллекции в foreach , ищет динамическое преобразование в IEnumerable (а затем выполняет преобразование из объекта, возвращенного Конечно, это актуально для типа переменной цикла.) Итак, ваш вопрос в основном таков: «Почему код, сгенерированный с использованием динамического типа в качестве типа коллекции foreach, не может найти шаблон во время выполнения?»
Поскольку это уже не 1999 год, и даже когда это было в дни C # 1.0, коллекции, которые использовали этот шаблон, также почти всегда реализовывали IEnumerable. Вероятность того, что реальный пользователь будет писать код производственного качества C # 4.0, который делает foreach над коллекцией, которая реализует шаблон, но не IEnumerable, чрезвычайно низка. Теперь, если вы находитесь в такой ситуации, это неожиданно, и мне жаль, что наш дизайн не смог удовлетворить ваши потребности. Если вы считаете, что ваш сценарий на самом деле распространен, и что мы неправильно оценили его редкость, пожалуйста, опубликуйте более подробную информацию о вашем сценарии, и мы рассмотрим возможность его изменения для гипотетических будущих версий.
Обратите внимание, что преобразование, которое мы генерируем в IEnumerable, - это динамическое преобразование, а не просто проверка типов. Таким образом, динамический объект может участвовать; если он не реализует IEnumerable, но желает предложить прокси-объект, который делает это, он может сделать это бесплатно.
Короче говоря, конструкция «динамического foreach» - это «динамически запрашивать объект для последовательности IEnumerable», а не «динамически выполнять каждую операцию тестирования типов, которую мы выполняли бы во время компиляции». Теоретически это слегка нарушает принцип проектирования, согласно которому динамический анализ дает тот же результат, что и статический анализ, но на практике мы ожидаем, что подавляющее большинство динамически доступных коллекций будут работать.