Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compiler Error for Expression/Func overloads

The screenshot says it pretty much. I have the overloads as seen in the screenshot. When using a string as second parameter the compiler should figure out that the first argument can only be a Func and not an expression. But the compiler throws an error saying 'A lamda expression with a statement body cannot be converted to an expression tree'.

Why can't the compiler figure out the correct overload?

Explicit cast does not help. What works is when i make a local variable of type Func and then use this instead.

The framework used is FakeItEasy 1.24.0

Wtf?

EDIT:

Here is the code that shows the behavior:

public static void Main(string[] args)
    {
        //compiler error
        A.CallTo(() => Main(A<string[]>.That.Matches(strings =>
                                                     {
                                                         return true;
                                                     }, "description")));

        //compiles
        Func<string[], bool> predicate = strings =>
                         {
                             return true;
                         };
        A.CallTo(() => Main(A<string[]>.That.Matches(predicate, "description")));

        Console.ReadLine();
    }
like image 617
cmart Avatar asked Jan 12 '15 12:01

cmart


1 Answers

The issue is not in the call to Matches. It's in the call to CallTo, which expects an Expression<Action>.

Apparently an Expression not only can't be a lambda expression with a statement body, it also can't contain a lambda expression with a statement body.

(I'm not sure whether your "put the lambda in a local variable" solution will work or whether it just tricks the compiler and will fail at runtime.)

Here's the test I put together:

static void Overloaded(Action a, string param) { }
static void Overloaded(Expression<Action> e) { }

static void CallToAction(Action a) { }
static void CallToExprAc(Expression<Action> a) { }

static void Main(string[] args)
{
    // Works
    CallToAction(() => Overloaded(() => { int i = 5; }, "hi"));

    // Doesn't work - using the Expression overload
    CallToAction(() => Overloaded(() => { int i = 5; }));

    // Doesn't work - wrapped in an outer Expression
    CallToExprAc(() => Overloaded(() => { int i = 5; }, "hi"));
}

Whether your "put the expression-bodied lambda in a local" works is up to how FakeItEasy is implemented. I suspect it'll work here, but something similar in e.g. LINQ-to-SQL wouldn't - it'd just fail at runtime rather than at compile time.

I'm not sure whether this is a compiler bug, a spec bug or desirable behaviour. In section 6.5 of the C# spec we have

Certain lambda expressions cannot be converted to expression tree types: Even though the conversion exists, it fails at compile-time. This is the case if the lambda expression:

• Has a block body

• Contains simple or compound assignment operators

• Contains a dynamically bound expression

• Is async

which doesn't say "contains a lambda expression that cannot be converted to an expression tree type".

like image 195
Rawling Avatar answered Oct 22 '22 05:10

Rawling