2015-01-12 9 views
7

Der Screenshot sagt es ziemlich viel. Ich habe die Überladungen wie auf dem Screenshot zu sehen. Wenn ein String als zweiter Parameter verwendet wird, sollte der Compiler herausfinden, dass das erste Argument nur ein Func und kein Ausdruck sein kann. Der Compiler gibt jedoch einen Fehler aus, der besagt, dass ein Lamda-Ausdruck mit einem Anweisungskörper nicht in einen Ausdrucksbaum konvertiert werden kann.Compiler Fehler für Ausdruck/Func Überladungen

Warum kann der Compiler die richtige Überladung nicht herausfinden?

Explizite Besetzung hilft nicht. Was funktioniert, ist, wenn ich eine lokale Variable vom Typ Func mache und diese stattdessen benutze.

Das Framework verwendet wird, ist FakeItEasy 1.24.0

Wtf?

EDIT:

Hier ist der Code, der das Verhalten zeigt:

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(); 
    } 
+4

könnten Sie den Code nicht screenshot posten? – mybirthname

+2

Sie verwenden 'return' nicht in einem Ausdruck-nur-Lambda-Körper ....' string => true' ist ausreichend. – leppie

+1

@leppie: richtig, das ist nicht der Punkt, obwohl. Wie Sie auf dem Screenshot sehen können, sollte der Compiler die Überladung mit einem Func verwenden und daher sollte ein Methodenhauptteil in Ordnung sein. Der Compiler gibt stattdessen einen Fehler aus. Die Frage ist warum. – cmart

Antwort

6

Die Frage ist nicht in der Anruf an Matches. Es ist in dem Anruf CallTo, der Expression<Action> erwartet.

Offenbar ein Expression nicht nur kein Lambda-Ausdruck mit einer Aussage Körper sein kann, kann es auch nicht enthält ein Lambda-Ausdruck mit einer Aussage Körper.

(Ich bin nicht sicher, ob Ihre „in einer lokalen Variablen, die Lambda-put“ Lösung wird Arbeit oder ob es nur die Compiler Trick und wird zur Laufzeit fehl.)

Hier ist der Test, den ich zusammen :

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")); 
} 

Ob Ihr „setzen Sie den Ausdruck-bodied Lambda in einem lokalen“ arbeitet, ist bis zu wie FakeItEasy umgesetzt wird. Ich vermute, dass es hier funktioniert, aber etwas Ähnliches in z.B. LINQ-to-SQL würde nicht - es würde nur zur Laufzeit statt zur Kompilierzeit fehlschlagen.

Ich bin nicht sicher, ob dies ein Compiler-Bug, ein Spezifikationsfehler oder wünschenswertes Verhalten ist. In Abschnitt 6.5 der C# -Spezifikation haben wir

Bestimmte Lambda-Ausdrücke können nicht in Ausdrucksbaumtypen konvertiert werden: Obwohl die Konvertierung vorhanden ist, schlägt sie bei der Kompilierung fehl. Dies ist der Fall, wenn der Lambda-Ausdruck:

• Hat einen Blockkörper

• Enthält einfache oder zusammengesetzte Zuweisungsoperator

• Enthält einen dynamisch gebundenen Ausdruck

• Ist async

die nicht sagen "enthält einen Lambda-Ausdruck, der nicht in einen Ausdrucksbaum ty konvertiert werden kann pe ".

+0

Ahh .. Guter Punkt! Und ja, es funktioniert auch zur Laufzeit, wenn Sie eine lokale Variable erstellen. Thx! – cmart

+0

@MarChr Froh, es zu hören, und guter Platz - sicherlich ein interessantes Problem zu betrachten. – Rawling

+0

Ja, aber es macht jetzt auch Sinn. Vielen Dank! – cmart