Выражение против проблем с предикатами - PullRequest
0 голосов
/ 25 мая 2009

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

По большей части, это так. Я, однако, немного озадачен. Я в коде ниже, пытаясь выполнить List.Find с динамически созданным выражением. Короче говоря, это выражение:

list.Find(m => m.ListOfStrings.Exists(s => s == "cookie"));

, где m равно

class MyClass
{
    public List<string> ListOfStrings { get; set; }
}

Я дошел до того, чтобы создать

s => s == "cookie"

с выражениями, без проблем. Я также объявил methodinfo для Exists

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

Это дает понятное исключение, что

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])'

Как, черт возьми, я могу это преодолеть?

Полный код:

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

Ответы [ 2 ]

2 голосов
/ 25 мая 2009

У делегатов разные типы:

public delegate bool Predicate<T>(T obj);
public delegate TResult Func<T, TResult>(T arg);

Метод ExistsFind) ожидают Predicate<T>. Лямбда-выражение компилируется во время выполнения в Func<T, TResult>.

Попробуйте следующее:

var existsLambda = Expression.Lambda(typeof(Predicate<string>), 
                Expression.Equal(
                    Expression.Parameter(typeof(string), "s"),
                    Expression.Constant("cookie")),
                Expression.Parameter(typeof(string), "s"));

Вы также можете использовать общую лямбда-функцию :

var existsLambda = Expression.Lambda<Predicate<string>>(Expression.Equal(
                    Expression.Parameter(typeof(string), "s"),
                    Expression.Constant("cookie")),
                Expression.Parameter(typeof(string), "s"));
0 голосов
/ 25 мая 2009

Если вы посмотрите на сообщение, оно говорит, что Predicate не совместим с Func.

Теперь предикат определяется так:

public delegate bool Predicate<T>(
    T obj
)

и у вас есть Func как таковой:

public delegate TResult Func<T, Result>(
    T arg1
)

Соберите, вы пытаетесь совместить этих двух делегатов:

public delegate bool MyClassPredicate ( MyClass obj )
public delegate bool StringFunc ( string arg1 )

Т.е.. строка! = MyClass.

Надеюсь, это имело смысл.

...