Подтвердить что ты не робот

Как динамически создавать предикат Expression <Func <MyClass, bool >> из выражения <Func <MyClass, string >>?

Я пытаюсь добавить, где предикаты и моя цель - создать такое же выражение, как:

Services.Where(s => s.Name == "Modules" && s.Namespace == "Namespace");

У меня есть следующий код:

Expression<Func<Service,string>> sel1 = s => s.Name;
Expression<Func<Service,string>> sel2 = s => s.Namespace;

var val1 = Expression.Constant("Modules");
var val2 = Expression.Constant("Namespace");

Expression e1 = Expression.Equal(sel1.Body, val1);
Expression e2 = Expression.Equal(sel2.Body, val2);
var andExp = Expression.AndAlso(e1, e2);

ParameterExpression argParam = Expression.Parameter(typeof(string), "s");
var lambda = Expression.Lambda<Func<string, bool>>(andExp, argParam);

Создайте следующий вывод:

s => ((s.Name == "Modules") AndAlso (s.Namespace == "Namespace"))

Однако это неверно, поскольку параметр Имя и Пространство имен не совпадает. Если я изменил один из селекторов выражений на:

Expression<Func<Service,string>> sel2 = srv => srv.Namespace;

Выход будет:

s => ((s.Name == "Modules") AndAlso (srv.Namespace == "Namespace"))

Как создать достоверное выражение с использованием sel1 и sel2?

ОБНОВЛЕНИЕ (28 фев 2011)

Я решил это, создав выражения invoke: Expression.Invoke, поэтому лямбда-выражения sel1 и sel2 не обязательно должны быть MemberExpression:

Expression<Func<Service,string>> sel1 = s => s.Name;
Expression<Func<Service,string>> sel2 = srv => srv.Namespace;

var val1 = Expression.Constant("Modules");
var val2 = Expression.Constant("Namespace");

Expression<Func<Service, bool>> lambda = m => true;
var modelParameter = lambda.Parameters.First();

// sel1 predicate
{
    var invokedExpr = Expression.Invoke(sel1, modelParameter);
    var binaryExpression = Expression.Equal(invokedExpr, val1);
    lambda = Expression.Lambda<Func<Service, bool>>(Expression.AndAlso(binaryExpression, lambda.Body), lambda.Parameters);
}
// sel2 predicate
{
    var invokedExpr = Expression.Invoke(sel2, modelParameter);
    var binaryExpression = Expression.Equal(invokedExpr, val2);
    lambda = Expression.Lambda<Func<Service, bool>>(Expression.AndAlso(binaryExpression, lambda.Body), lambda.Parameters);
}
4b9b3361

Ответ 1

Трудно смешивать генерируемые компилятором деревья выражений и созданные вручную, именно из-за такого рода вещей - извлечение ParameterExpressions сложно. Итак, начните с нуля:

ParameterExpression argParam = Expression.Parameter(typeof(Service), "s");
Expression nameProperty = Expression.Property(argParam, "Name");
Expression namespaceProperty = Expression.Property(argParam, "Namespace");

var val1 = Expression.Constant("Modules");
var val2 = Expression.Constant("Namespace");

Expression e1 = Expression.Equal(nameProperty, val1);
Expression e2 = Expression.Equal(namespaceProperty, val2);
var andExp = Expression.AndAlso(e1, e2);

var lambda = Expression.Lambda<Func<Service, bool>>(andExp, argParam);

Один важный аспект, который я изменил, - это тип, переданный в Expression.Parameter - он определенно выглядит как Service, а не string.

Я дал эту попытку, и, похоже, она срабатывала, когда я вызывал lambda.Compile и выполнял ее на нескольких образцах Service объектов...