I'm not sure exactly what you are asking for; but at least I can try to provide some insights into the difference between Expression
and lambda functions, both of which are language features of the mainstream .NET languages (C#, VB.NET).
Basically, a lambda function is an anonymous (unnamed) function that can be declared inside the scope of another function. In C# (language version 3), it would be declared like this:
(
parameter list )
=>
function body
For example:
void Foo()
{
// two equivalent lambda functions with one double parameter 'x' each:
var square = (double x) => x * x;
var square2 = (double x) => { return x * x; };
// lambda function that doesn't take any arguments:
var doSomething = () => { Console.WriteLine("Hello."); }
}
(Note that e.g. square
is not the name of the lambda function, but of the variable that references it. The lambda function itself does not have any name in the way that method void Foo()
has!)
Something very similar was already possible with C# version 2, called anonymous delegates:
delegate(double x) { return x * x; } // is equivalent to: (double x) => x * x
Expressions were added to .NET with LINQ (in the namespace System.Linq.Expressions
). Basically, they're simple data structures that describe, as an abstract syntax tree (AST), any computation as can be expressed e.g. with C# or VB.NET. Take for example:
// case 1. IEnumerable<int>:
IEnumerable<int> xs = ...;
IEnumerable<int> queryXs = from x in xs where x > 0 select x;
// case 2. IQueryable<int>:
IQueryable<int> ys = ...;
IEnumerable<int> queryYs = from y in ys where y > 0 select y;
These two queries are identical, except that ys
is of type IQueryable<int>
instead of IEnumerable<int>
. The C# compiler will translate the above two queries into different code, namely:
// case 1. IEnumerable<int>:
IQueryable<int> xs = ...;
IEnumerable<int> queryXs = xs.Where<int>(delegate (int x) { return x > 0; });
// case 2. IQueryable<int>:
IEnumerable<int> ys = ...;
ParameterExpression yParameter = Expression.Parameter(typeof(int), "y");
IEnumerable<int> queryYs.Where<int>(
Expression.Lambda<Func<int, bool>>(
Expression.GreaterThan(
yParameter,
Expression.Constant(0, typeof(int))),
new ParameterExpression[] { yParameter }));
If you study the latter, you will see that for the query of the IQueryable<int>
, the compiler has output the parsed query as a data structure that describes the query. On the other hand, for the query against IEnumerable<int>
, it has simply output code that performs the query. It turns out that the compiler does the special magic of producing what it has parsed as an expression tree only with the IQueryable<T>
type.
Expressions and IQueryable<T>
therefore allow you to analyse a query at run-time and perform optimizations and other transformations on it before it is actually run. This is heavily used e.g. by LINQ to SQL to write intelligent, optimized SQL queries:
Imagine a database was asked for all rows where some column x
is > 0.
If the database were an IEnumerable<int>
(that really is simplifying it a lot, I know, but bear with me), all rows would have to be fetched and then filtered by the .Where(delegate (int x) { ... })
method.
If the database were an IQueryable<int>
, the Expression
output by the compiler would be analysed and transformed into an SQL query at run-time such that it would include an appropriate WHERE x > 0
clause and only produce the desired rows right away.
If you're interested in the internals of / parsing expression trees, have a look at the in-depth blog series by Bart De Smet, starting with The IQueryable tales - LINQ to LDAP - Part 0: Introduction.