Converting Delegates to Expression Trees 9

Posted by Jb Evain Wed, 22 Apr 2009 19:03:00 GMT

Plage du diamant

Back when I was working at db4o, we had fun implementing a mechanism somehow similar to LINQ, to have strongly typed queries expressed using code itself. The implementation uses Mono.Cecil and Cecil.FlowAnalysis to decompile a delegate into an AST, that db4o’s query optimizer can process.

Since .net 3.5, an API, System.Linq.Expressions, can be used to get a representation of a C# lambda expression into an object graph. An expression tree. .net 4.0 will add support for statements to this API, but as far as I know, the language itself hasn’t been updated to produce those new nodes.

Anyway, a few days ago, someone on Stack Overflow, asked how to turn a delegate into a LINQ expression tree. There’s no builtin feature to do that, it’s not a straightforward process. You basically have to decompile the compiled method. I guess it’s a good thing that I’m working on a decompiler, if I need to decompile something.

Tonight I wrote a short spike to verify the feasibility of my idea, and it turns out to be pretty simple. Sample:

static void Main ()
{
    Func<int, int> magic = i => i * 42;

    Expression<Func<int, int>> expression =
        DelegateConverter.ToExpression (magic);

    Console.WriteLine (expression.ToString ());
    // prints: i => i * 42
    Console.WriteLine (expression.Compile ().Invoke (1));
    // prints: 42
}

DelegateConverter is implemented as a simple visitor which walks over a Cecil.Decompiler AST, and generates, if possible, the according Linq Expression Tree. Pretty cool isn’t it?

You can browse the code of the spike. Keep in mind that it’s nowhere to be complete, and that it’s just a proof of concept. Still, I think it’s a pretty cool usage of the Cecil.Decompiler library.

Trackbacks

Use the following link to trackback from your own site:
http://evain.net/blog/articles/trackback/559

  1. Thank you for submitting this cool story - Trackback from DotNetShoutout
Comments

Leave a response

  1. Avatar
    Rodrigo B. de Oliveira Wed, 22 Apr 2009 21:30:14 GMT

    Nice.

  2. Avatar
    Seth Wed, 22 Apr 2009 21:43:31 GMT

    It most certainly is [Pretty cool]

    Scratches head and thinks how this will end world famine, diseases and noisy neighbours in the end

  3. Avatar
    Jb Evain Wed, 22 Apr 2009 21:51:16 GMT

    Seth, let us know your findings. I mean, that would make it extra cool. Bonus point if you take into accounts the neighbour’s dog.

  4. Avatar
    Arne Claassen Wed, 22 Apr 2009 21:54:55 GMT

    Cool. I just ran into just that same scenario the other night. I wanted to serialize my lambdas across the wire, but ended up to just using Expression> instead of Func as my argument. The drawback is that now i have to compile the expression when i want to use it, instead of just invoking it. So if the call doesn’t cross the wire that’s extra overhead. Haven’t done any testing to see if that’s significant or not.

  5. Avatar
    Bojan R. Thu, 23 Apr 2009 02:53:16 GMT

    Only one suggestion—make it an extension method, for extra-clean code (and chaining!) :)

  6. Avatar
    Jb Evain Thu, 23 Apr 2009 08:25:16 GMT

    I did not in a first place as you can’t constrain a generic parameter on the type Delegate.

  7. Avatar
    Vincent B. Thu, 23 Apr 2009 13:51:57 GMT

    Yes that’s Pretty cool !

  8. Avatar
    Yann Schwartz Thu, 23 Apr 2009 15:41:31 GMT

    Nifty.

    Now if we could have full delegate to full AST (statement + expressions) this would be pure unadultered bliss. ExpressionTree are for pure expressions but I’m sure there’s something in Cecil.Decompiler that would care for both expressions and statements…

  9. Avatar
    Jb Evain Thu, 23 Apr 2009 15:43:47 GMT

    Cecil.Decompiler already provides you with a full fledged AST, here we’re just transforming it into a LINQ expression tree, because we can do it :)

    We’ll even be able to extend that to the new statements nodes of the LINQ expression tree for .net 4.0.

Comments