Assigning a Func to an Expression and vice versa

Mehmet Ataş picture Mehmet Ataş · Jan 5, 2013 · Viewed 12.4k times · Source

I was tampering with Expressions and I got confused at some points

  1. We can assign same LamdaExpression to both Expression and/or Func. But we cannot assign a Func to an Expression (or an Expression to Func). Why cannot we do that? I looked for if a conversion operator between Expression and Func is defined but I could not found any.

    Func<int, int> sumFunc            = i => i + i;
    Expression<Func<int, int>> sumExp = i => i + i;
    
    // sumExp = sumFunc; // Cannot convert source type 'System.Func<int,int>' to target type 'System.Linq.Expressions.Expression<System.Func<int,int>>'
    // sumFunc = sumExp; // Cannot convert source type 'System.Linq.Expressions.Expression<System.Func<int,int>>' to target type 'System.Func<int,int>'
    
  2. Even we cannot assign a LambdaExpression to an object. Again, why cannot we do that?

    // object o = i => i + i; // Cannot convert source type 'lambda expression' to target type 'object'
    
  3. I think there is something about compiler. If so, can we write our custom types those behave in this (confusing) manner and take advantage of something.

Answer

Desty picture Desty · Jan 6, 2013

Regarding to the C# Language Specification a lambda expression like

i => i + i

is an anonymous function. An expression with this classification can be implicitly converted to a compatible delegate type or expression tree type. This is why you can write both

Func<int, int> sumFunc            = i => i + i;
Expression<Func<int, int>> sumExp = i => i + i;

The first is a delegate type, the second an expression tree type. Because there is no implicit converting between those types, you cannot assign sumFunc = sumExp or vice versa. But since the expression tree sumExp represents a lambda expression, you can compile that expression to an executable delegate and assign it to sumFunc, because this is such a compatible delegate:

sumFunc = sumExp.Compile();

The other direction is not possible, because a delegate cannot easily be "decompiled" into an expression tree.

The reason why you cannot write

object o = i => i + i;

is, that an anonymous function does not have a value or type in and of itself, it is just convertible to a delegate or expression tree type. You have to tell the compiler which of both you want, so you can convert it at first and then assign the result to a variable of type object:

object sumFuncObject = (Func<int, int>) (i => i + i);
object sumExpObject = (Expression<Func<int, int>>) (i => i + i);

Regarding your last question: You can create custom implicit or explicit conversions between complex types, so that this "magic" can be applied to assignments. See the Conversion Operations Programming Guide for more information.