Utilisez string.Compare (a, b) dans Expression

c# expression expression-trees

Question

Je me suis enseigné Expression Trees depuis hier et j'ai du mal à comparer deux valeurs de chaîne. J'ai créé ce scénario de test qui échoue avec l'erreur:

No method 'Compare' on type 'System.String' is compatible with the supplied arguments.

Échoue au moment de l'exécution à left = Expression.Call(

Type type = typeof(string);
Expression left, right;
left = Expression.Constant("1", type);
right = Expression.Constant("2", type);
// fails at run-time on the next statement
left = Expression.Call(
    typeof(string),
    "Compare",
    new Type[] { type, type },
    new Expression[] { left, right });
right = Expression.Constant(0, typeof(int));

Je vais utiliser le résultat Expression.Equal, LessThan, LessThanOrEqual, GreaterThan or GreaterThanOrEqual dans les Expression.Equal, LessThan, LessThanOrEqual, GreaterThan or GreaterThanOrEqual . C'est la raison de la méthode Compare.

Je suis sûr que c'est quelque chose de simple, et j'ai résumé mon code à ce cas de test simple. Quelqu'un voit où je me suis trompé?

Réponse acceptée

C'est le problème dans votre code Expression.Call :

new Type[] { type, type },

Cela essaye d'appeler string.Compare<string, string> - ce sont les arguments génériques , pas les types des paramètres normaux. Étant donné qu'il s'agit d'une méthode non générique, utilisez simplement null ici.

Programme court mais complet:

using System;
using System.Linq.Expressions;

class Test
{
    static void Main()
    {
        var left = Expression.Constant("1", typeof(string));
        var right = Expression.Constant("2", typeof(string));
        var compare = Expression.Call(typeof(string),
                                      "Compare",
                                      null,
                                      new[] { left, right });
        var compiled = Expression.Lambda<Func<int>>(compare).Compile();
        Console.WriteLine(compiled());
    }
}

Réponse populaire

J'essayais de faire la même chose que la clause lambda where ( LINQ to SQL ), et depuis que différentes recherches m'ont atterri sur cette page, je vais donc partager une telle solution ici au cas où elle aiderait les autres à atterrir ici.

Il est plus facile de simplifier ce que vous faites avec une expression générique de Compare .

    public static Expression CompareLessThanOrEqualTo(Expression e1, Expression e2)
    {
        var compare = Expression.Call(typeof(string),
                           "Compare",
                           null,
                           new[] { e1, e2 });

        return Expression.LessThanOrEqual(compare, Expression.Constant(0));
    }

Ensuite, vous pouvez utiliser cette expression comme n'importe quelle autre

    public static Expression<Func<TypeOfParent, bool>> PropertyLessThanOrEqualString<TypeOfParent, String>(PropertyInfo property, String value)
    {
        var parent = Expression.Parameter(typeof(TypeOfParent));
        var expressionBody = CompareLessThanOrEqualTo(Expression.Property(parent, property), Expression.Constant(value));
        return Expression.Lambda<Func<TypeOfParent, bool>>(expressionBody, parent);
    }

Sorcière peut être utilisé comme

public static IQueryable<T> ApplyFilters<T>(this IQueryable<T> query, List<GridFilters> gridFilters)
{
    // foreach filter
        // Get property (propertyInfo)
        // Get Value(s)
        // Apply Filter
        query = query.Where(PropertyLessThanOrEqualString<T, string>(propertyInfo, value1));

    // ...

    return query;
}

Ceci est utile si vous devez appliquer une liste de filtres choisis par l'utilisateur, dans laquelle les valeurs et les opérateurs peuvent être tous deux choisis. (Commence par, contient, entre la plage)



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow