2016-08-17 9 views
0

Вот код.Что делает компилятор C# выводить дерево выражений вместо кода?

int[] data = new int[] { 1, 2, 3, 4, 5 }; 
    var q1 = data.Select(x => 10 * x); 
    var q2 = data.AsQueryable().Select(x => 10 * x); 
    Expression<Func<int,int>> qe = (x) => 10 * x; 

В первом случае компилятор генерирует код для оценки выражения. На выходе нет дерева выражений.

Во втором он генерирует дерево выражений (видимое при отладке), которое во время выполнения компилируется и выполняется для выполнения запроса (и делает то же самое).

В третьем случае такая же лямбда как (2) создается непосредственно как дерево выражений (а не как код).

Что заставляет компилятор генерировать дерево выражений вместо кода в этих двух случаях, и есть ли другие интересные случаи?

Причина: я хочу «выделить» верхний уровень дерева выражений во время выполнения, а затем скомпилировать и выполнить нижние уровни. У меня возникли проблемы с тем, чтобы заставить компилятор делать все по-моему!

+2

Это случай «так написано компилятором». Это нужно сделать так, чтобы заставить выражения работать. Это похоже на методы, возвращающие 'IEnumerable ' может использовать 'yield return'. Специальные операции компилятора для поддержки языковых функций. – Enigmativity

+0

Этот список можно продолжить. Компилятор обрабатывает 'Nullable ' типы по-разному. Он может использовать утиную печать для циклов foreach. Запросы LINQ - это просто переупорядоченные методы (обычно это метод расширения, но не обязательно). 'using' заявления работают только с расходными материалами и т. д. – Enigmativity

+0

Ваше первое утверждение не является выражением; это вызов конструктора *. Два оператора Select - это выражения Linq, которые выражают как часть их нормальной работы. Четвертый оператор генерирует выражение, потому что вы указали выражение как результирующий тип. –

ответ

3

Enumerable44 метод принимает параметр типа Func<TSource,TResult>. Queryable способ Select принимает параметр типа Expression<Func<TSource,TResult>>.

Это так просто: если у компилятора есть лямбда-выражение, он может либо генерировать выражение, либо компилировать лямбда, и это решение основано на том, что его просят создать - если это Expression какого-то типа, это будет генерировать дерево выражений. Если это Func или другой тип делегата, он генерирует код.

+0

Черт! Это действительно настолько просто! Компилятор генерирует код, если параметр получен из Делегата и дерева выражений, если он получен из выражения, и других вариантов нет. Благодаря! –

+1

Просто имейте в виду, что делегаты могут охватывать несколько строк, но дерево выражений, которое написано так же, как делегат, например. 'Expression > lambda =() => new int [] {1, 2, 3, 4, 5};' может быть только одной строкой. – Sagi