I was tampering with Expressions and I got confused at some points
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>'
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'
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.
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.