Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are lambda expression arguments ambiguous between Func and Expression<Func>?

Tags:

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?

like image 291
Jeffrey Sax Avatar asked Nov 26 '11 18:11

Jeffrey Sax


People also ask

What is the use of lambda expression in C#?

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.

What is expression in Linq?

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.

What is expression tree in C#?

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.


1 Answers

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.

like image 196
João Angelo Avatar answered Oct 14 '22 03:10

João Angelo