Динамический лямбда-код для метода Where в linq

#c# #linq #lambda

#c# #linq #лямбда

Вопрос:

Мне интересно, как динамически передавать свойство объекта как часть лямбды, которая будет использоваться в Where методе IQueryable .

Предположим, у меня есть этот код:

 var list = new List<Item>();
...

var filtered = list.AsQueryable().Where(x => x.SomePropertyA.Contains(someStringValue));
 

Моя задача — сделать последнее утверждение в качестве универсального метода и использовать параметр:

 IQueryable<Item> SomeMethod(Expression<Func<Item, string>> expr, string stringValue) {

     return list.AsQueryable().Where (???);
}

SomeMethod(x => x.SomePropertyA, someStringValue);
SomeMethod(x => x.SomePropertyB, someStringValue);
 

Мои интуиции подсказывают мне, что мне придется использовать класс Expressions для вызова Contains метода строки, возвращаемой expr , но я не уверен, как это сделать, поскольку я не очень хорошо знаком с этим…

Комментарии:

1. во время выполнения вы выбираете, какое свойство передавать методу?

2. Метод будет использоваться в нескольких местах, с разными объектами и разными свойствами. Задача состоит в том, чтобы сделать метод как можно более универсальным.

3. вы можете использовать отражение , чтобы получить нужное свойство

Ответ №1:

Этот метод создаст требуемое выражение:

 static Expression<Func<T, bool>> CreateContainsPredicate<T>(Expression<Func<T, string>> property, string value)
{
    return Expression.Lambda<Func<T, bool>>( // Where() wants this kind of expression
        Expression.Call(                     // we need to call method
            property.Body,                   // on instance returned by passed expression
            typeof(string).GetMethod("Contains", new [] { typeof(string) }), // call 'Contains()'
            Expression.Constant(value)),     // pass value to Contains() method
        property.Parameters);                // resulting expression has same parameters as input expression
}
 

Использование:

 IQueryable<Item> SomeMethod(Expression<Func<Item, string>> expr, string stringValue) {
    return list.AsQueryable().Where(CreateContainsPredicate<Item>(expr, stringValue));
}
 

Комментарии:

1. Фантастика, именно то, что мне нужно!