Используйте string.Compare(a, b) в выражении

Со вчерашнего дня я обучаю себя деревьям выражений, и у меня возникают проблемы при сравнении двух строковых значений. Я сделал этот контрольный пример, который завершается с ошибкой:

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

Сбой во время выполнения на 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));

Я буду использовать полученный левый и правый в Expression.Equal, LessThan, LessThanOrEqual, GreaterThan or GreaterThanOrEqual, В этом причина метода сравнения.

Я уверен, что это что-то простое, и я свел свой код к этому простому тестовому примеру. Кто-нибудь видит, где я ошибся?

2 ответа

Решение

Это проблема в вашем Expression.Call код:

new Type[] { type, type },

Вот пытаюсь позвонить string.Compare<string, string> - это общие аргументы, а не типы нормальных параметров. Учитывая, что это не универсальный метод, просто используйте ноль здесь.

Короткая, но полная программа:

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

Я пытался сделать то же самое, что и предложение лямбда-где (LINQ to SQL), и, поскольку различные поиски высадили меня на этой странице, я поделюсь таким решением здесь на тот случай, если оно поможет другим, кто приземлится здесь.

Это проще всего, когда вы упрощаете то, что делаете, с помощью общего выражения сравнения.

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

Тогда вы можете использовать это выражение, как и любой другой

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

Ведьма может быть использована, например,

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

Это полезно, если у вас есть список фильтров, выбранных пользователем, которые необходимо применить, где можно выбрать значения и операторы. (Начинается с, содержит, между диапазонами)

Другие вопросы по тегам