Assigning a Func to an Expression and vice versa

13,399

Solution 1

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.

Solution 2

Actually both of these expressions are syntax sugar, transformed by compiler in different language constructions.

When you write lambda expression, compiler does this: makes member function that matches your lamda expression and assigns it to your sumFunc variable (this is not exact code, just to get an idea):

class Program
{
   private static int generatedname(int i)
   {
        return i + i;
   }

   static void Main()
   {
       Func<int, int> sumFunc = generatedname;
   } 
}

When you write Expression tree there is even more magic happens. At compile time compiler transforms your expression into Expression tree "construction". Like this.

class Program
{
    static void Main()
    {
        var addPrm = Expression.Parameter(typeof(int), "i");
        Expression<Func<int, int>> sumExp = 
            Expression.Lambda<Func<int, int>>(
                Expression.Add(
                    addPrm,
                    addPrm
                ),
                addPrm
            );
    } 
}

You see this is completely different things, thats why you can not simply cast one to another.

Share:
13,399
Mehmet Ataş
Author by

Mehmet Ataş

Updated on June 12, 2022

Comments

  • Mehmet Ataş
    Mehmet Ataş almost 2 years

    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.

  • Yinda Yin
    Yinda Yin over 11 years
    Why wouldn't it be possible? Surely you can iterate through the abstract syntax tree and generate a recursive collection of objects. Whether that's at all useful is another question.
  • doug65536
    doug65536 over 11 years
    Sure it would be possible. There is probably a much better way, but at worst you could reverse engineer the IL (programmatically) and generate an expression tree. But why?
  • doug65536
    doug65536 over 11 years
    I'm pretty sure if you make them a real method (instead of lambda), you can use a single "invoke" node in the expression tree to run the function. If you need arbitrary lambdas, I'm not sure off hand how to do that.