Ответ 1
Согласно Эрику Липперту, анонимные итераторы не были добавлены к языку, потому что было бы слишком сложно реализовать его.
Это не совсем то, что я хотел передать. Соответствующая стоимость - это стоимость внедрения, да, но это стоимость реализации в существующем компиляторе, который не был настроен архитектурно для реализации этой сложной функции.
Компилятор должен сделать то же самое для async-методов, как и для итераторов (преобразовать их в конечные машины), поэтому я очень смущен, почему анонимные итераторы также недопустимы, когда используются анонимные методы async.
Краткая история имеет значение. Сначала на С# были анонимные методы и блоки итераторов в С# 2.0. Когда я добавил lambdas в С# 3.0, это была большая стоимость для реорганизации всего существующего кода анонимного метода, чтобы он мог обрабатывать все новые функции lambdas. Это сделало его еще более сложным и дорогостоящим. Создание блока итератора lambdas было оценено слишком дорого для преимуществ, которые будут начислены; это был бы большой процент от общей стоимости. Мы не могли себе это позволить.. Если вы добавили каждую команду в расписание работы отдела разработчиков, команда с "самым длинным полюсом" была командой компилятора С# 3.0, и моя работа над семантическим анализатором была IIRC самый длинный полюс в команде компилятора. Каждый день мы, возможно, пропустили С# 3.0, это был бы тот день, когда Visual Studio поскользнулась. Поэтому все, что не делало LINQ лучше, было разрезано, и это включало итератор lambdas.
В С# 4 итератор лямбда был одной из многих особенностей, которые были рассмотрены. У нас был список потенциальных хороших функций буквально дольше, чем у вас, и мы могли позволить себе делать менее десятой части.
В С# 5 команда добавила асинхронные методы. Группы проектирования и внедрения долгое время пытались найти базовую абстракцию, которая была общей для блока итератора и ожидала перезаписывания; они, очевидно, похожи, как вы заметили. Но, в конечном счете, стоимость поиска общего решения не оплачивалась сама по себе. Общепринятость на удивление дорогостоящая, и нахождение общности в том, что по дизайну объединяет только две вещи, глупо, если это не дешево.
Поэтому было принято решение реализовать ожидающий переписывающий как свою собственную вещь. Учитывая, что команда собирается взять на себя эту большую стоимость и учитывая, что первоначальная трансформация асинхронных методов будет в любом случае состоять в форме лямбда, было принято решение инвестировать в полную функцию: асинхронные методы, содержащие лямбды, асинхронные лямбды содержащий лямбда, всю сделку. Стоимость этой функции была небольшой частью стоимости всей функции, что было чрезвычайно дорого.
И снова у нас проблема с длинными полюсами. Любые работы с лямбда-движком, которые потенциально могут быть дестабилизированы await
, следует избегать, и это включает попытку заставить их работать с блоками итератора.
Теперь сравните Visual Basic. У VB долгое время не было блоков итераторов. Когда они были добавлены, не было существующей инфраструктуры, чтобы продолжать работать! Все это можно было бы построить с нуля, чтобы обрабатывать блоки итератора, содержащие лямбды и лямбда, содержащие блоки итераторов, и так было сделано.
Компилятор С# был тщательно зашифрован и переписан через проект Roslyn. Я надеюсь, что это снизит стоимость реализации блока итератора lambdas в гипотетической будущей версии С#. Мы увидим!