58 votes

Créer une expression à partir d'une fonction

J'ai un Func<TCollection, T> dans mon code. Je l'utilise pour sélectionner certaines propriétés.

Dans un appel à une autre méthode, j'ai besoin de Expression<Func<TCollection, T>> comme paramètre.

Existe-t-il un moyen de convertir (ou de créer à partir de) Func<TCollection, T> a Expression<Func<TCollection, T>> ?

Merci

1 votes

63voto

Polity Points 7316

Vous ne pouvez pas recréer une expression sur la base d'une méthode, car une expression doit connaître les déclarations d'origine, et non IL. Vous pouvez cependant créer une expression qui fait un appel de méthode à votre func comme :

Func<int> func = () => 1;
Expression<Func<int>> expression = Expression.Lambda<Func<int>>(Expression.Call(func.Method));

Il convient toutefois de noter que les systèmes tels que EF ne peuvent pas vraiment fonctionner avec cela

2 votes

En supposant que vous c Cependant, pour obtenir l'IL, vous pouvez décompiler l'IL, comme le font Reflector et ILSpy. (Bien sûr, il n'y a aucune garantie que ce soit exactement le même que le code à partir duquel l'IL a été compilé). Existe-t-il un moyen d'accéder à l'IL d'un délégué ?

6 votes

Je pense que vous devez ajouter la cible de la fonction dans votre appel. J'ai essayé avec un Func<> plus complexe et il s'est plaint que j'essayais d'appeler une méthode d'instance avec un objet null. Je l'ai remplacé par Expression.Call(Expression.Constant(func.Target), func.Method, args) et tout est rentré dans l'ordre.

0 votes

EF peut s'en accommoder s'il est bien cuisiné. voir stackoverflow.com/a/40958545/292787

39voto

Jon Skeet Points 692016

Pendant que vous c créer un arbre d'expression qui appelle votre délégué, il est peu probable que cela soit utile - parce que le délégué sera essentiellement une boîte noire en ce qui concerne le code qui analyse l'arbre d'expression. En supposant que vous essayiez d'utiliser quelque chose comme LINQ to SQL, l'analyseur de requêtes devra être capable de pénétrer dans votre logique pour la convertir en SQL - et il ne peut pas le faire s'il atteint un simple délégué.

Vous devriez probablement modifier le code qui génère le délégué en premier lieu, pour créer un arbre d'expression à la place.

33voto

Simon Points 2419

Vous pouvez faire quelque chose comme ça :

Func<object, string> func = a => a.ToString();
Expression<Func<object, string>> expr = a => func(a);

Mais vous n'obtiendrez qu'une expression contenant votre appel de méthode au Func original. Vous ne pourrez pas analyser le contenu de la fonction elle-même.

4 votes

Mais bien entendu, M. Skeet l'exprime bien mieux que moi ! :-)

3 votes

Vous dites cela, mais votre réponse est celle qui m'a semblé logique le matin après la nuit passée à faire l'aller-retour à l'aéroport.... Cette réponse résume bien l'idée qu'un func est quelque chose qui peut être appelé, et qu'une expression est un appel à un func.

9voto

George Mavritsakis Points 2778

Vous ne pouvez pas créer une expression à partir d'un délégué (de Func<TCollection, T> a Expression<Func<TCollection, T>> ), mais vous pouvez faire le contraire.

En d'autres termes, il s'agit de convertir un Expression<Func<TCollection, T>> a un Func<TCollection, T> en le compilant ( .compile ).

Ainsi, si vous avez besoin des deux, vous pouvez utiliser des expressions dans vos fonctions et, le cas échéant, les compiler et les exécuter sur un objet de collection fourni.

Il faut bien sûr noter que la compilation d'une expression est lente.

0 votes

C'est exactement ce dont j'avais besoin. J'essayais juste de réduire la duplication du code. Il semble que je l'ai regardé de la mauvaise façon.

0 votes

Si l'on veut éviter la duplication du code, c'est la bonne solution.

0voto

F.Çetin Points 1

Créez une classe comme ci-dessous ;

 public class GenericFilter<T> where T : class, new()
    {
        public Expression<Func<T, bool>> Filter = item => true;

    }

Utilisation ;

var filter=new GenericFilter<blabla>().Filter.And(x=>...);
filter=filter.And(x=>...);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X