Догадки Томаса довольно хороши. Его рассуждения о методах расширения точны. По сути, чтобы заставить методы расширения работать, нам нужно, чтобы сайт вызова во время выполнения каким-то образом знал, какие директивы использования были в силе во время компиляции. У нас просто не было достаточно времени или бюджета для разработки системы, с помощью которой эта информация могла бы сохраняться на сайте вызова.
Для лямбда-выражений ситуация на самом деле сложнее, чем простая проблема определения того, идет ли лямбда к дереву выражений или к делегату. Рассмотрим следующее:
d.M(123)
где d — выражение динамического типа. * Какой объект должен передаваться во время выполнения в качестве аргумента для сайта вызова «M»? Ясно, что мы боксируем 123 и пропускаем его. Затем алгоритм разрешения перегрузки в связующем времени выполнения просматривает тип времени выполнения d и тип времени компиляции int 123 и работает с этим.
А что, если бы это было
d.M(x=>x.Foo())
Какой же объект мы должны передать в качестве аргумента? У нас нет способа представить «лямбда-метод одной переменной, который вызывает неизвестную функцию с именем Foo для любого типа x».
Предположим, мы хотим реализовать эту функцию: что нам нужно будет реализовать? Во-первых, нам нужен способ представления несвязанной лямбда-выражения. Деревья выражений предназначены только для представления лямбда-выражений, в которых известны все типы и методы. Нам нужно изобрести новый вид «нетипизированного» дерева выражений. Затем нам нужно будет реализовать все правила привязки лямбда-выражений в связывателе времени выполнения.
Рассмотрим последний пункт. Лямбды могут содержать операторы. Для реализации этой функции требуется, чтобы компоновщик времени выполнения содержал полный семантический анализатор для каждого возможного оператора в C#.
Это было на порядок больше нашего бюджета. Мы бы до сих пор работали над C# 4, если бы захотели реализовать эту функцию.
К сожалению, это означает, что LINQ не очень хорошо работает с динамическими, потому что LINQ, конечно же, повсюду использует нетипизированные лямбда-выражения. Будем надеяться, что в какой-то гипотетической будущей версии C# у нас будет более полнофункциональное средство связывания времени выполнения и возможность создавать гомоиконические представления несвязанных лямбда-выражений. Но на твоем месте я бы не стал ждать, затаив дыхание.
ОБНОВЛЕНИЕ: комментарий просит разъяснения по поводу семантического анализатора.
Рассмотрим следующие перегрузки:
class C {
public void M(Func<IDisposable, int> f) { ... }
public void M(Func<int, int> f) { ... }
...
}
и звонок
d.M(x=> { using(x) { return 123; } });
Предположим, что d имеет динамический тип времени компиляции и тип времени выполнения C. Что должен делать компоновщик времени выполнения?
Связыватель времени выполнения должен определить во время выполнения, можно ли преобразовать выражение x=>{...}
в каждый из типов делегатов в каждой из перегрузок M.
Для этого связующее время выполнения должно иметь возможность определить, что вторая перегрузка неприменима. Если бы это было применимо, вы могли бы иметь int в качестве аргумента для оператора использования, но аргумент для оператора использования должен быть одноразовым. Это означает, что компоновщик во время выполнения должен знать все правила для оператора using и быть в состоянии правильно сообщить, является ли любое возможное использование оператора using законным или незаконным.
Ясно, что это не ограничивается оператором using. Связыватель среды выполнения должен знать все правила для всего языка C#, чтобы определить, можно ли преобразовать данную лямбда-выражение в данный тип делегата.
У нас не было времени написать исполняющую компоновку, которая по сути представляла бы собой полностью новый компилятор C#, генерирующий деревья DLR, а не IL. Не допуская лямбда-выражений, нам нужно только написать компоновщик времени выполнения, который знает, как связывать вызовы методов, арифметические выражения и несколько других простых типов сайтов вызовов. Разрешение лямбда-выражений делает проблему привязки во время выполнения порядка десятков или сотен раз более дорогостоящей для реализации, тестирования и обслуживания.
person
Eric Lippert
schedule
28.08.2010
Method
и не являетсяIEnumarable
. Я не вижу тех вещей, которые вы назвали ограничениями, возможно, вы и автор не поняли, что делаетdynamic
. - person BrunoLM   schedule 28.08.2010