Problèmes Expression vs Predicate

.net-3.5 c# expression-trees lambda

Question

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());
}

Réponse acceptée

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"));

Réponse populaire

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.



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