An expression tree is an efficient data representation of a query operator lambda expression. This data representation is evaluated all simultaneously, so that an individual query can be built and launched on a data source in once
Consider the next query with two operators expecting delegates as arguments:
When the first code is compiled .NET IL emits code with two anonymous methods, one for each of the query lambda expressions
This query is evaluated and launched linearly, first Where operator, then OrderBy operator. This linear evaluation has performance for this example, but consider a query on a large dataset. These scena is when Expression Trees become necessary. Expression trees will be generated if the operator is declared to accept an expression of a delegate
These are the two different implementations of the Where operator:
Standard query operator in LINQ to Objects API, in System.Linq.Enumerable class
Implementation in the LINQ to SQL API, in the System.Linq.Queryable class
The result of this code is the next
The ease way to create expression trees is by using advanced LINQ features, however, a tree made up only of constans would be converted automatically at compile time, the aim is build parametric expressions, such as the formula to convert celsius to kelvin degrees : K = C + 273.15
The first delegate instance is no different from a regular function, you can get an expression tree representation instead of the delegate simply declaring CelsiusToKelvin as an Expression<TDelegate>
The result of this code is the next
Consider the next query with two operators expecting delegates as arguments:
private static decimal[] celsiusDegrees = new decimal[]
{0.0M, 6.0M, 14.0M, 25.0M, 28.0M, 34.0M, 36.0M};
private static IEnumerable<decimal> enumerableTemps = celsiusDegrees
.Where(i => i > 30.0M)
.OrderBy(i => i).ToArray();
private static IQueryable<decimal> queryableTemps = celsiusDegrees.Where(c => c > 30.0M)
.OrderBy(c => c).AsQueryable();
When the first code is compiled .NET IL emits code with two anonymous methods, one for each of the query lambda expressions
This query is evaluated and launched linearly, first Where operator, then OrderBy operator. This linear evaluation has performance for this example, but consider a query on a large dataset. These scena is when Expression Trees become necessary. Expression trees will be generated if the operator is declared to accept an expression of a delegate
These are the two different implementations of the Where operator:
Standard query operator in LINQ to Objects API, in System.Linq.Enumerable class
public static IEnumerable<T> Where<T>(
this IEnumerable<T> source,
Func<T, bool> predicate);
Implementation in the LINQ to SQL API, in the System.Linq.Queryable class
public static IQueryable<T> Where<T>(
this IQueryable<T> source,
System.Linq.Expressions.Expression<Func<int, bool>> predicate);
The result of this code is the next
Console.WriteLine(enumerableTemps);
foreach (var temp in enumerableTemps)
Console.WriteLine(temp);
Console.WriteLine(Environment.NewLine);
Console.WriteLine(queryableTemps);
foreach (var temp in queryableTemps)
Console.WriteLine(temp);
The ease way to create expression trees is by using advanced LINQ features, however, a tree made up only of constans would be converted automatically at compile time, the aim is build parametric expressions, such as the formula to convert celsius to kelvin degrees : K = C + 273.15
Func<decimal, decimal> CelsiusToKelvin = (c) => c + 273.15M;
Expression<Func<decimal, decimal>> CelsiusToKelvinExp = (c) => c + 273.15M;
The first delegate instance is no different from a regular function, you can get an expression tree representation instead of the delegate simply declaring CelsiusToKelvin as an Expression<TDelegate>
The result of this code is the next
Console.WriteLine(CelsiusToKelvin.ToString());
Console.WriteLine(CelsiusToKelvin(34.2M));
Console.WriteLine(CelsiusToKelvinExp.ToString());
Console.WriteLine(CelsiusToKelvinExp.Compile()(34.2M));