Analyser la condition booléenne dans l'arbre d'expression

c# expression-trees linq

Question

Si j'ai une méthode qui prend un booléen comme:

public void Foo(boolean condition)

Et appelez ça comme ça:

Foo("MyField" == "MyValue");

Puis-je composer cela dans un arbre d'expression afin de construire une requête vers une autre source de données qui utilisera MyField en tant que paramètre et MyValue et une autre. Je ne peux que sembler faire de cette condition une expression dont le résultat est faux.

METTRE À JOUR

    var param = Expression.Parameter(typeof(Field), field);
    var prop = Expression.PropertyOrField(param, "Name");

    ConstantExpression @const = Expression.Constant(value, typeof(string));
    var body = Expression.Equal(prop, @const);
    var lambda = Expression.Lambda<Func<Field, bool>>(body, param);

Où Field est une classe avec deux propriétés, Name et Value

Réponse acceptée

Foo("MyField" == "MyValue") est, comme indiqué au bas de la question, une constante false (jusqu'au compilateur). Vous avez quelques choix ici - le plus simple bien sûr est de faire quelque chose comme:

void Foo(Expression<Func<YourType,bool>> predicate) {...}

et appeler avec

Foo(x => x.MyField == "MyValue");

alors ici , il n'y a plus rien à faire; nous avons déjà l'expression. Donc, je suppose que vous voulez dire que "MyField" est une chaîne uniquement connue à l'exécution, auquel cas:

void Foo<T>(string fieldName, T value) {
   var param = Expression.Parameter(typeof(YourType), "x");
   var body = Expression.Equal(
                  Expression.PropertyOrField(param, fieldName),
                  Expression.Constant(value, typeof(T))
               );
   var lambda = Expression.Lambda<Func<YourType, bool>>(body, param);
}

et appelez avec Foo("MyField", "MyValue) (avec une <string> implicite dedans, gracieuseté du compilateur), ou avec Foo("MyField", 123) si le prop est un int (implicite <int> ),

Le scénario final est celui où "MyValue" est également une chaîne connue uniquement à l'exécution (emph: string ). Dans ce cas, nous devrons l'analyser:

void Foo(string fieldName, string value) {
   var param = Expression.Parameter(typeof(YourType), "x");
   var prop = Expression.PropertyOrField(param, fieldName);
   ConstantExpression @const;
   if(prop.Type == typeof(string)) {
       @const = Expression.Constant(value, typeof(string));
   } else {
       object parsed = TypeDescriptor.GetConverter(prop.Type)
           .ConvertFromInvariantString(value);
       @const = Expression.Constant(parsed, prop.Type);
   }
   var body = Expression.Equal(prop,@const);
   var lambda = Expression.Lambda<Func<YourType, bool>>(body, param);
}

Ici l'appel est toujours Foo("MyField", "123") 2 chaînes - donc Foo("MyField", "123") même lorsque int .


Réponse populaire

Dans peut créer des arbres d'expression à partir de délégués. Par exemple, si vous définissez votre méthode de telle sorte qu'elle utilise un délégué comme paramètre, vous pouvez l'utiliser comme suit:

public void Foo(Func<bool> fn)
{
    // invoke the passed delegate
    var result = fn();
}

Foo(() => "MyField" == "MyValue");

Afin de créer un arbre d’expression plutôt que d’exécuter le délégué, changez la méthode comme suit:

public void Foo(Expression<Func<bool>> expression)
{
   // inspect your expression tree here
}

Cependant, dans votre cas, vous constaterez que votre expression est une constante booléenne avec la valeur 'false', car le compilateur a évalué "MyField" == "MyValue" qui est bien sûr faux.

Si vous voulez juste des paires nom-valeur, n'utilisez pas un Dictionary<string, string> ?




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