views:

125

answers:

4

I was thinking about the difference between Expression<Func<>> and Func<>, and wondered if you could convert a static method to an expression tree as follows:

class Program
{
    static void Main(string[] args)
    {
        Func<int, int> t = x => hrm(x);
        Func<int, int> t2 = new Func<int, int>(hrm);

        // Works as expected:
        Expression<Func<int, int>> et = x => hrm(x);
        // Brokenness:
        Expression<Func<int, int>> et2 = new Func<int, int>(hrm);
    }

    static int hrm(int x)
    {
        return x + 9;
    }
}

What's so special about the second "Func<>" that it can't be converted to an Expression, when the first one can?

+1  A: 

My understanding:
A lambda can be either represent an Expression or a delegate/Action/Func.
The first sample works, because the left side makes sure that you want an Expression.
The second sample doesn't work, because you create a Func<> explicitly on the right side.

Benjamin Podszun
+4  A: 

I think your confusion comes from the fact that lambdas can represent expressions or delegates (with the very same syntax) in C#. So this code:

x => hrm(x)

means something different depending on where it's written. When assigned to Func<int, int>, it's compiled as normal to create a Func<int, int> delegate. However, when assigned to an expression, the C# compiler defers compilation and the snippet is interpreted as an expression. Contrast this with new Func<int, int>(hrm), which always returns a Func<int, int> delegate.

Sean Devlin
Thanks, itowlson. I am not the master of markdown.
Sean Devlin
Picky point: it's not quite that "expressions and lambdas are syntactically equivalent," but that "lambdas representing expressions and lambdas representing delegates are syntactically equivalent." Both are still lambdas. But good explanation of the general point that the compiler treats a lambda differently depending what it returns into.
itowlson
You're right. I'll correct it.
Sean Devlin
Got it .. thanks :)
+1  A: 

Only lambda expression are convertible into expression trees. This is why your second option won't compile.

You can create an expression tree to represent the invocation of hrm() - but it would either be via a lambda or by creating the AST by hand. Furthermore, in neither case is the body of the hrm() ever available as an expression tree - if that's what you were looking to do.

LBushkin
That is actually what I was looking to do, but I had a good idea it wasn't going to be that easy.
A: 

I'd recommend you to take a look at these two blog posts: Expression Tree Basics by Charlie Calvert and my own post Generating Dynamic Methods with Expression Trees in Visual Studio 2010.

These should give you some idea about expression trees syntax and what they can and cannot do.

Alexandra Rusina