Perché dovresti usare Expression > piuttosto che Func ?

c# delegates expression-trees lambda

Domanda

Capisco lambda e i delegati di Func e Action . Ma le espressioni mi bloccano. In quali circostanze Expression<Func<T>> piuttosto che una semplice Func<T> ?

Risposta accettata

Quando vuoi trattare le espressioni lambda come alberi di espressione e guardarle dentro invece di eseguirle. Ad esempio, LINQ to SQL ottiene l'espressione e la converte nell'istruzione SQL equivalente e la invia al server (anziché eseguire il lambda).

Concettualmente, Expression<Func<T>> è completamente diversa da Func<T> . Func<T> denota un delegate che è praticamente un puntatore a un metodo e Expression<Func<T>> denota una struttura di dati dell'albero per un'espressione lambda. Questa struttura ad albero descrive cosa fa un'espressione lambda piuttosto che fare la cosa reale. Praticamente contiene dati sulla composizione di espressioni, variabili, chiamate di metodo, ... (per esempio contiene informazioni come questa lambda è un parametro costante + qualche parametro). È possibile utilizzare questa descrizione per convertirla in un metodo effettivo (con Expression.Compile ) o altre cose (come l'esempio LINQ in SQL) con esso. L'atto di trattare lambda come metodi anonimi e alberi di espressione è puramente una questione di tempo compilativo.

Func<int> myFunc = () => 10; // similar to: int myAnonMethod() { return 10; }

compilerà in modo efficace un metodo IL che non ottiene nulla e restituisce 10.

Expression<Func<int>> myExpression = () => 10;

sarà convertito in una struttura dati che descrive un'espressione che non ottiene parametri e restituisce il valore 10:

Espressione vs Func immagine più grande

Mentre entrambi hanno lo stesso aspetto al momento della compilazione, ciò che genera il compilatore è completamente diverso .


Risposta esperta

LINQ è l'esempio canonico (ad esempio, parlando con un database), ma in verità, ogni volta che ti interessi di più sull'esprimere cosa fare piuttosto che farlo effettivamente. Ad esempio, utilizzo questo approccio nello stack RPC di protobuf-net (per evitare la generazione del codice ecc.), Quindi chiami un metodo con:

string result = client.Invoke(svc => svc.SomeMethod(arg1, arg2, ...));

Questo decostruisce l'albero delle espressioni per risolvere SomeMethod (e il valore di ogni argomento), esegue la chiamata RPC, aggiorna eventuali argomenti di ref / out e restituisce il risultato dalla chiamata remota. Questo è possibile solo tramite l'albero delle espressioni. Lo copro di più qui .

Un altro esempio è quando si costruiscono manualmente gli alberi di espressioni allo scopo di compilarli in una lambda, come fatto dal codice generico degli operatori .



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché