Pourquoi voudriez-vous utiliser Expression? <Func<T> &gt; plutôt que Func <T> ?

c# delegates expression-trees lambda

Question

Je comprends lambdas et les délégués Func et Action . Mais les expressions me bouchent. Dans quelles circonstances utiliseriez-vous une Expression<Func<T>> plutôt qu'un simple vieux Func<T> ?

Réponse acceptée

Lorsque vous souhaitez traiter les expressions lambda comme des arbres d'expression et regarder à l'intérieur de celles-ci au lieu de les exécuter. Par exemple, LINQ to SQL obtient l'expression et la convertit en instruction SQL équivalente et la soumet au serveur (plutôt que d'exécuter le lambda).

Conceptuellement, Expression<Func<T>> est complètement différente de Func<T> . Func<T> désigne un delegate qui est en gros un pointeur sur une méthode et Expression<Func<T>> désigne une structure de données arborescente pour une expression lambda. Cette arborescence décrit ce que fait une expression lambda plutôt que de faire la chose réelle. Il contient essentiellement des données sur la composition d'expressions, de variables, d'appels de méthodes, ... (par exemple, il contient des informations telles que ce lambda est une constante + un paramètre). Vous pouvez utiliser cette description pour la convertir en méthode réelle (avec Expression.Compile ) ou effectuer d'autres opérations (comme l'exemple LINQ to SQL). Traiter les lambdas comme des méthodes et des arbres d'expression anonymes est purement une tâche de compilation.

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

sera effectivement compilé en une méthode IL qui n'obtient rien et retourne 10.

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

sera converti en une structure de données qui décrit une expression qui n’obtient aucun paramètre et renvoie la valeur 10:

Expression vs Func image plus grande

Bien qu'ils se ressemblent tous les deux lors de la compilation, le compilateur génère une création totalement différente .


Réponse d'expert

LINQ est l'exemple canonique (par exemple, parler à une base de données), mais en vérité, chaque fois que vous vous souciez davantage d'exprimer ce qu'il faut faire, plutôt que de le faire réellement. Par exemple, j’utilise cette approche dans la pile RPC de protobuf-net (pour éviter la génération de code, etc.) - vous appelez donc une méthode avec:

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

Cela déconstruit l'arborescence d'expression pour résoudre SomeMethod (et la valeur de chaque argument), effectue l'appel RPC, met à jour les arguments ref / out et renvoie le résultat de l'appel distant. Ceci n'est possible que via l'arbre d'expression. Je couvre cela plus ici .

Un autre exemple est lorsque vous construisez manuellement les arbres d'expression dans le but de les compiler en lambda, comme le fait le code d' opérateur générique .




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi