Compiler Error for Expression/Func overloads
Asked Answered
B

1

8

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();
    }
Buy answered 12/1, 2015 at 12:22 Comment(8)
could you post the code not screenshot ?Gadolinite
You dont use return in an expression-only lambda body.... string => true is sufficient.Heelandtoe
@leppie: correct, that is not the point though. As you can see in the screenshot the compiler should use the overload with a Func <string[],bool> and therefore a method body should be fine. The compiler gives an error instead. The question is why.Buy
@MarChr: Obviously Expression has higher precedence than Func. IQueryable would be pretty useless if it was the other way around.Heelandtoe
@leppie: The second parameter is a string so therefore the overload with the expression should be out of the picture because this overload has only 1 parameter.Buy
@MarChr: Sorry, did not notice that. Does the string parameter have a default value perhaps?Heelandtoe
@leppie: Good point, but no default value.Buy
Since I think this is a compiler bug, I've raised it here.Leeanneleeboard
L
6

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".

Leeanneleeboard answered 12/1, 2015 at 13:9 Comment(4)
Ahh.. Good point! And yes, it also works at runtime when you make a local variable. Thx!Buy
@MarChr Glad to hear it, and good spot - certainly an interesting problem to look at.Leeanneleeboard
Yes, but it also makes sense now. Thank you!Buy
Since I think this is a compiler bug, I've raised it here.Leeanneleeboard

© 2022 - 2024 — McMap. All rights reserved.