views:

84

answers:

1

Hi ;)

I've recently implemented an IronRuby web service application for a client, to replace an existing C# .NET DLL. What the client forgot to mention was that in the mean time they implemented a new version of the DLL, with a new API based on lambda expressions. And made sure all calls (thousands :( ) use the new syntax. So now I need to implement a replacement .NET DLL which receives Func/Actions and executes them on a remote server.

Now I'm a Ruby/Perl guy and have little knowedge of advanced .NET. I don't quite get the difference between Expressions and lambas. I know LINQ to SQL can execute expressions on a remote SQL server. Can it execute lambdas too? Can I use the same approach (whatever it is) in my scenario?

Generally any pointers/ideas/solutions are welcome.

Thanks, Frederik

+2  A: 

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.

stakx