J'ai un peu de mal à créer un arbre d'expression pour représenter une requête de l'utilisateur. Étant donné que je n'ai pas le temps de créer tous les cas possibles de saisie de l'utilisateur, j'ai pensé que les arbres d'expression me permettraient de résoudre ce problème.
Pour la plupart, il a. Je suis cependant un peu perplexe. Je suis dans le code ci-dessous essayer d'exécuter un List.Find avec une expression créée dynamiquement. En bref, l'expression est la suivante:
list.Find(m => m.ListOfStrings.Exists(s => s == "cookie"));
où m est
class MyClass
{
public List<string> ListOfStrings { get; set; }
}
J'ai eu jusqu'à créer
s => s == "cookie"
avec des expressions, pas de problème. J'ai aussi déclaré un methodinfo pour Exists
var existsMethod = typeof(MyClass)
.GetProperty("ListOfStrings")
.PropertyType
.GetMethod("Exists");
Le seul problème que j'ai est de créer une expression pour invoquer ladite méthode avec le lambda en tant que paramètre tel que
var findLambda = Expression.Lambda(
Expression.Call(
Expression.Property(
Expression.Parameter(typeof(MyClass), "m"),
typeof(MyClass).GetProperty("ListOfStrings")),
existsMethod,
existsLambda),
Expression.Parameter(
typeof (MyClass),
"m"));
Il donne une exception compréhensible que
Expression of type 'System.Func`2[System.String,System.Boolean]' cannot be used for parameter of type 'System.Predicate`1[System.String]' of method 'Boolean Exists(System.Predicate`1[System.String])'
Comment diable puis-je surmonter cela?
Code complet:
private class MyClass
{
public List<string> ListOfStrings { get; set; }
}
public void SomeMethod()
{
var myObject = new MyClass();
myObject.ListOfStrings = new List<string>();
myObject.ListOfStrings.Add("cookie");
myObject.ListOfStrings.Add("biscuit");
List<MyClass> list = new List<MyClass>();
list.Add(myObject);
var existsLambda = Expression.Lambda(
Expression.Equal(
Expression.Parameter(typeof(string), "s"),
Expression.Constant("cookie")),
Expression.Parameter(typeof(string), "s"));
var existsMethod = typeof(MyClass).GetProperty("ListOfStrings").PropertyType.GetMethod("Exists");
var findLambda = Expression.Lambda(
Expression.Call(
Expression.Property(
Expression.Parameter(typeof(MyClass), "m"),
typeof(MyClass).GetProperty("ListOfStrings")),
existsMethod,
existsLambda),
Expression.Parameter(
typeof (MyClass),
"m"));
list.Find((Predicate<MyClass>)findLambda.Compile());
}
Les délégués ont différents types:
public delegate bool Predicate<T>(T obj);
public delegate TResult Func<T, TResult>(T arg);
La méthode Exists
(et la Find
) s’attendent à Predicate<T>
. L'expression Lambda est compilée au moment de l'exécution en Func<T, TResult>
.
Essayez ce qui suit:
var existsLambda = Expression.Lambda(typeof(Predicate<string>),
Expression.Equal(
Expression.Parameter(typeof(string), "s"),
Expression.Constant("cookie")),
Expression.Parameter(typeof(string), "s"));
Vous pouvez également utiliser la fonction Lambda générique:
var existsLambda = Expression.Lambda<Predicate<string>>(Expression.Equal(
Expression.Parameter(typeof(string), "s"),
Expression.Constant("cookie")),
Expression.Parameter(typeof(string), "s"));
Si vous regardez le message, il vous dit que Predicate n'est pas compatible avec Func.
Maintenant, Predicate est défini comme tel:
public delegate bool Predicate<T>(
T obj
)
et vous avez Func en tant que tel:
public delegate TResult Func<T, Result>(
T arg1
)
Ensemble, vous essayez de rendre ces 2 délégués compatibles:
public delegate bool MyClassPredicate ( MyClass obj )
public delegate bool StringFunc ( string arg1 )
C'est à dire. chaîne! = MyClass.
J'espère que cela avait du sens.