2015-01-02 5 views
2

На самом деле четыре связанных вопроса:Где неявный литье из TDelegate в выражение <TDelegate>?

1) Почему это возможно?

Expression<Func<int, int>> incrementorExpression = (i => i + 1); 

Но не быть в состоянии это сделать?

LambdaExpression decrementorExpression = (i => i - 1); 

Во втором случае, сообщения компилятора, таким образом: «Не удается преобразовать лямбда-выражения к типу„System.Linq.Expressions.LambdaExpression“, потому что это не тип делегата»

2) Где является листинг между TDelegate и Expression<TDelegate>? Кажется, я помню, что видел это в прошлом, но, похоже, не могу найти его сейчас. Но я не могу быть уверен, видел ли я это или нет.

3) Когда я делаю это:

Expression<Func<int, int>> incrementExpression = (i => ++i); 

Компилятор говорит, "Выражение дерево не может содержать оператор присваивания." Почему это так?

4) И потом, если я могу это сделать:

Expression<Func<int, int>> incrementorExpression = (i => i + 1); 

Тогда почему я не могу сделать this?

public Expression<Func<T>> ToExpression<T>(Func<T> func) 
{ 
    return func; 
} 
+0

Я не думаю, что 3 принадлежит: 'i => (i = i + 1)' на самом деле не представляет собой выражение ... –

+0

Но '++ i' просто означает' return (i + 1) '. Это не означает «i = i + 1». 'i + = 1' не будет выражением, так как это будет означать' i = i + 1', и это будет утверждение. –

+1

Это новости для меня ... '++ i' is' {i = i + 1; return i;} 'Насколько мне известно ... –

ответ

6

Вы почти нашли ответ уже.

i => i + 1 не является Func<int, int>. Это лямбда-выражение. Лямбда-выражения могут быть преобразованы в соответствующий тип делегата или соответствующий тип дерева выражений.

Если выражение лямбда преобразуется в тип делегата, компилятор компилирует его в код IL, который имеет указанный эффект.

Если выражение лямбда преобразуется в тип дерева выражений, компилятор компилирует это в ИЛ, который генерирует дерево выражений, которое представляет то, что вы написали в своем лямбда-выражении. Деревья выражений предназначены для последующего анализа библиотеками, поэтому важно, чтобы дерево выражений соответствовало написанному вами коду.

Func<int, int> f = i => i + 1; // okay, creates delegate. 
Expression<Func<int, int>> e = i => i + 1; // okay, creates expression tree. 

Никакая информация не может быть получена из f об операции он выполняет. Из его типа делегата известно, что он принимает int и возвращает int, но кроме этого это черный ящик. Вы ввели номер, и вы получили номер, но вы уже не знаете, как это сделать.

e, с другой стороны, сохраняет тот факт, что 1 добавляется параметр с именем i, и даже на РИТ в +1, что появляется.

Эта дополнительная информация, которая хранится в e не часто необходим те библиотеки, которые интерпретируют дерева выражений, так что неявное преобразование из Func<int, int> в Expression<Func<int, int>> просто не будет работать: требуемая информация больше недоступна.

Что касается LambdaExpression decrementorExpression = (i => i - 1);, что является недопустимым просто потому, что нет никакого способа для компилятора, чтобы определить, хотите ли вы Expression<Func<int, int>>, Expression<Func<int, object>>, или Expression<MyFunc> где MyFunc типа пользовательского делегата вы создали.

И, наконец, «Дерево выражений может не содержать оператор присваивания», это главным образом потому, что для предполагаемых вариантов использования деревьев выражений, как правило, не имеет смысла для выражения содержать назначение. Это несколько произвольное ограничение, хотя, учитывая, что деревья выражений .NET способны представлять операции присваивания.

+0

спасибо. –

+0

Отличный ответ! +1 –

0

Вот некоторые мыслительные фрагменты, которые на мой взгляд, и они помогают решить некоторые загадки. Но я все еще жду ответа.

Прежде всего, i => i + 1 не является Func<int, int> или Func ничего. Последний - ИЛ; Func - IL; TDelegate - IL. От IL до выражения не существует никакого пути.

Первый - это выражение. Некоторое текстовое представление выражения lamda .

Теперь, даже если это так, должно быть какое-то отличное от этого типа текстового типа вещь i => i + 1 до Expression<TDelegate>?

Но я думаю, что нет, потому что нет синтаксического токена для представления текста i => i + 1. Должен быть какой-то класс, представляющий это в DOM компилятора, но в LINQ Expression API ничего подобного нет для такого рода вещей. И поэтому компилятор использует свой собственный АСТ, чтобы знать: «О, я только что встречался с таким текстом. Позвольте мне разобрать его и превратить в Expression».

Но это все, что у меня есть, который, если это правда, отвечает только на часть моего вопроса. Все еще ждут решения остальной части головоломки.