Reputation: 3214
Question similar to one by John K, but more specific and the accepted answer doesn't suit my needs.
This compiles fine:
Expression<Func<object, object>> specificExpression = (object o) => new object();
Expression generalExpression = specificExpression;
And this one doesn't:
Expression generalExpression = (object o) => new object();
Reported compile error:
Cannot convert lambda expression to type 'System.Linq.Expressions.Expression' because it is not a delegate type
Expression<Func<T1,T2>>
derives from Expression
.
Now I have a framework with methods accepting all sorts of expressions, i.e. type Expression
. Being forced to explicitly cast lambdas to the corresponding Expression<Func<T1,T2>>
on each method call is frustrating.
Any good reasons why this basic OOP behavior is broken in this case?
Upvotes: 2
Views: 3670
Reputation: 41256
The C# compiler evaluates the expression to the least complex form, for example:
var x = (object o) => new object();
x
should be a Func<object, object>
, not an Expression<Func<object, object>>
. In this case, the compiler is determining the value is a delegate, and since Expression
cannot take a delegate (only the Expression<Func<>>
/ Expression<Action>
types can), the compiler error is thrown.
Also, see @Riana's answer, because the expression form is actuall rewritten by the compiler.
Upvotes: 0
Reputation: 689
When you write
Expression<Func<object, object>> specificExpression = (object o) => new object();
It is actually an ease of writing that the C# compiler offers to us.
This expression will actually be compiled to something like this :
Expression.Lambda<Func<object, object>> specificExpression = Expression.Lambda<Func<object,object>> ( ... )
and as you can see, Expression<Func<object,object>>
is not a delegate type even if the first expession could induce us in error and let us believe that this is the case.
"Expression" is not of delegate type, so you can't assign it directly a delegate object because the compiler doesn't offer the ease of writing (as it does for Expression<T>
classes).
Sorry to say that but you have to go the frustrating way.
Riana
Upvotes: 0
Reputation: 169353
The conversion doesn't work because the compiler cannot infer which specific expression type you are trying to create. What if you did this?
Expression generalExpression = (object o) => "foo";
Should this be an Expression<Func<object, string>>
? What about Expression<Func<object, object>>
or Expression<Func<object, IComparable>>
? These types would all be a valid final type for the expression tree, and the compiler doesn't pretend to know what you are trying to do.
You need to cast through the specific type to inform the compiler which type of expression you want to produce:
Expression generalExpression = (Expression<Func<object, object>>)
(object o) => new object();
You would see a similar compiler error if you tried this:
Delegate generalDelegate = delegate() { };
Is that an Action
, or a ThreadStart
, or some other kind of no-argument void-returning delegate?
Upvotes: 8