2013-01-12 14 views
5

Perché expr1 compila ma non expr2?Perché un tipo di espressione in .NET consente la costruzione da una funzione ma non la conversione da una?

Func<object> func =() => new object(); 
Expression<Func<object>> expr1 =() => new object(); 
Expression<Func<object>> expr2 = func; //Cannot implicitly convert type 'System.Func<object>' to 'System.Linq.Expressions.Expression<System.Func<object>>' 
+1

Un sacco di buone spiegazioni su livelli inferiori ma ricordati che puoi sempre fare questo se si adatta alle vostre esigenze: 'Func func =() => nuovo oggetto(); Espressione > expr2 =() => func(); ' – JLRishe

risposta

4

Un Func<T> è un delegato (un puntatore a una funzione), mentre un Expression<Func<T>> è un albero di espressione (una struttura di dati ad albero che descrive un'operazione). Ne consegue che non è possibile assegnarne una all'altra, in quanto sono completamente dissimili.

Quando si assegna una funzione lambda direttamente a Func<T> il compilatore compila il codice per la propria funzione e assegna un puntatore al codice compilato per es. func.

D'altra parte, quando si assegna una funzione lambda direttamente a un Expression<Func<T>> il compilatore crea l'albero delle espressioni (che è semplicemente un'istanza di un tipo di riferimento) e assegna un riferimento a tale oggetto ad es. expr1. Questa è solo una comodità che il compilatore fornisce all'utente, offrendoti un'opzione molto più attraente della costruzione manuale dell'albero delle espressioni in codice (che ovviamente è anche completamente possibile).

+0

Ah ma, naturalmente, il compilatore vede tipi diversi (non correlati). E suppongo che il compilatore non sia in grado di "esaminare" 'func' per scoprire che si tratta di un'espressione lambda (puoi probabilmente dire che non sono un progettista di compilatori)? – Christian

+2

@Christian a lambda non ha tipo CLR. Non è possibile "memorizzare" un lambda ovunque. Puoi convertirlo in qualcos'altro ma non è più una lambda. Vedi la mia risposta. – usr

0

Perché System.Func<object> e System.Linq.Expressions.Expression<System.Func<object>> sono diversi tipi. Non puoi convertirli implicitamente.

Func<T> è un delegato. Guarda da MSDN.

Incapsula un metodo che non ha parametri e restituisce un valore di il tipo specificato dal parametro T.

Expression<Func<T>> è un albero di espressioni.

+0

Allora perché expr1 è legale? – miniBill

+1

@miniBill Perché C# consente la conversione implicita da un lambda a uno dei due tipi. – JLRishe

+1

Ha senso, grazie :) – miniBill

3

Non è possibile effettuare la conversione tra i tipi Func e Expression. Ma puoi convertire da un lambda a uno di essi.

Un lambda ha un tipo speciale che esiste solo nel sistema di tipo C#. Il CLR non sa cos'è un lambda. Solo il compilatore C# lo sa e le uniche operazioni che puoi fare con un lambda è convertire i tipi Func e Expression. (Ciò significa che non è possibile richiamare un lambda ad esempio perché non ha alcun tipo di CLR).

Ecco perché si osserva un "vuoto semantico" qui.

2

In parole semplici il compilatore può convertire un blocco di codice (Lambda espressione) in

  • un Expression
  • o un Func

Questo avviene immediatamente quando usato, quindi il codice è andato, convertito non reversibile. Ma Func e Expression sono tipi completamente diversi.

Ecco perché non è possibile

Expression<Func<object>> expr2 = func; 

Ma il contrario avrebbe lavorato con

Func<object> func2 = expr1.Compile(); 
Problemi correlati