Suppose I have a class:
class MyClass { public int MyMethod(Func<int, int> f) { return 0; } public int MyMethod(Expression<Func<int, int>> f) { return 1; } }
When I try to call the method with a lambda expression, I get a compile error stating that the call is ambiguous between the two overloads:
var myClass = new MyClass(); myClass.MyMethod(x => 1 + x); // Error!
while, of course, calling with an explicit type works fine:
myClass.MyMethod((Func<int, int>)(x => 1 + x)); // OK, returns 0 myClass.MyMethod((Expression<Func<int, int>>)(x => 1 + x)); // OK, returns 1
The expression tree contains more information (the actual code), and I may want to make use of this information when it is available. But I also want my code to work with delegates. Unfortunately, this ambiguity makes it so I have to find another way to distinguish between the two calls, which messes up an otherwise clean API.
The C# spec doesn't say anything about this specific situation, so in this sense the behavior does match the spec.
However, there is an argument to be made that the expression tree should be preferred over the delegate. The Compile
method acts as an explicit conversion from an expression tree to a delegate. The expression tree contains more information, and when you compile to a delegate, you lose that information. There is no conversion in the other direction.
Are there any reasons not to prefer the expression tree?
Lambda expressions and tuples The C# language provides built-in support for tuples. You can provide a tuple as an argument to a lambda expression, and your lambda expression can also return a tuple. In some cases, the C# compiler uses type inference to determine the types of tuple components.
LINQ introduced the new type called Expression that represents strongly typed lambda expression. It means lambda expression can also be assigned to Expression<TDelegate> type. The . NET compiler converts the lambda expression which is assigned to Expression<TDelegate> into an Expression tree instead of executable code.
Expression trees represent code in a tree-like data structure, where each node is an expression, for example, a method call or a binary operation such as x < y . You can compile and run code represented by expression trees.
Answering the question on the title, they are ambiguous because the type system has no concept of "lambda expression". It's a compiler feature which can be converted to a delegate or an expression tree so you need to be explicit to which type you want to convert it. Most of the times the target is also inferred automatically by the compiler because of the context in which the lambda expression is used. For example, the use of lambdas in IEnumerable
extension methods versus the use of lambdas in IQueryable
extension methods.
Now, to answer the question on why not always prefer the expression tree, you have the performance argument that MagnatLU already stated. If you accept an Expression
and then call Compile
to be able to execute it, then it will always be slower when compared to accepting a delegate.
There is also a semantic difference between the two, a delegate is just a way to execute some code while an expression tree is a description of the actual code.
If I were you I would opt to change the name of the method accepting the expression to something that clearly reflects what it does extra to the delegate based one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With