2015-01-12 11 views
7

Lo screenshot lo dice più o meno. Ho i sovraccarichi visti nello screenshot. Quando si usa una stringa come secondo parametro, il compilatore dovrebbe capire che il primo argomento può essere solo un Func e non un'espressione. Ma il compilatore genera un errore che dice "Un'espressione lamda con un corpo di istruzioni non può essere convertita in un albero di espressioni".Errore del compilatore per sovraccarichi di espressione/Func

Perché il compilatore non riesce a capire il sovraccarico corretto?

Il cast esplicito non aiuta. Ciò che funziona è quando faccio una variabile locale di tipo Func e poi uso questo.

Lo schema utilizzato è FakeItEasy 1.24.0

Wtf?

EDIT:

Ecco il codice che mostra il comportamento:

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

potresti pubblicare il codice non screenshot? – mybirthname

+2

Non si usa 'return' in un corpo lambda di sola espressione ....' string => true' è sufficiente. – leppie

+1

@leppie: corretto, non è questo il punto. Come puoi vedere nello screenshot, il compilatore dovrebbe usare l'overload con Func e quindi un metodo dovrebbe essere corretto. Il compilatore dà invece un errore. La domanda è perché. – cmart

risposta

6

Il problema non è in la chiamata a Matches. È nella chiamata a CallTo, che si aspetta un Expression<Action>.

apparentemente un Expression non solo non può essere un'espressione lambda con un corpo dichiarazione, può anche non contenere un'espressione lambda con un corpo dichiarazione.

(non sono sicuro se il vostro "mettere lambda in una variabile locale" soluzione lavoro o se esso solo inganna il compilatore e non riuscirà a runtime.)

Ecco il test che ho messo insieme :

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

sia che il vostro "mettere il lambda espressione di corpo in un locale" funziona è fino a come FakeItEasy è implementato. Sospetto che funzionerà qui, ma qualcosa di simile, ad es. LINQ-to-SQL non lo farebbe: fallirebbe solo in fase di esecuzione piuttosto che in fase di compilazione.

Non sono sicuro se si tratta di un bug del compilatore, un bug di specifiche o un comportamento desiderabile. Nella sezione 6.5 del C# spec abbiamo

Certe espressioni lambda non possono essere convertiti in tipi di alberi di espressione: Anche se esiste la conversione, non riesce a tempo di compilazione. Questo è il caso se l'espressione lambda:

• Ha un corpo del blocco

• Contiene operatori semplici o composti di assegnazione

• contiene un'espressione legata dinamicamente

• È asincrona

che non dice "contiene un'espressione lambda che non può essere convertita in un albero di espressione pe".

+0

Ahh .. Buon punto! E sì, funziona anche in runtime quando si crea una variabile locale. Thx! – cmart

+0

@ MarChr Felice di sentirlo, e buon posto - sicuramente un problema interessante da guardare. – Rawling

+0

Sì, ma ha anche senso ora. Grazie! – cmart