如何动态创建 Expression<Func<MyClass, bool>>表达式<Func<MyClass, string>中的谓词? [英] How do I dynamically create an Expression&lt;Func&lt;MyClass, bool&gt;&gt; predicate from Expression&lt;Func&lt;MyClass, string&gt;&gt;?

查看:30
本文介绍了如何动态创建 Expression<Func<MyClass, bool>>表达式<Func<MyClass, string>中的谓词?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图附加 where 谓词,我的目标是创建与以下相同的表达式:

I trying to append where predicates and my goal is to create the same expression as:

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

然而,这是错误的,因为NameNamespace 的参数不一样.如果我将表达式选择器之一更改为:

However, this is faulty since the parameter for Name and Namespace isn't the same. If I change one of the expression selector to:

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

输出将是:

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

如何使用 sel1sel2 创建有效的表达式?

How can I create a valid expression with use of sel1 and sel2?

更新(2011 年 2 月 28 日)

我通过创建调用表达式解决了这个问题:Expression.Invoke 所以 lambda 表达式 sel1 和 sel2 不需要是 MemberExpression:

I solved it by creating invoke expressions: Expression.Invoke so the lambda expressions sel1 and sel2 don't necessary need to be a 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);
}

推荐答案

很难混合编译器生成的表达式树和手工制作的表达式树,正是因为这种事情 - 提取 ParameterExpressions 很棘手.所以让我们从头开始:

It's hard to mix compiler-generated expression trees and hand-made ones, precisely because of this sort of thing - extracting out the ParameterExpressions is tricky. So let's start from scratch:

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.

One important aspect I've changed is the type passed to Expression.Parameter - it certainly looks like it should be a Service rather than a string.

我已经试过了,当我调用 lambda.Compile 并在几个示例 Service 对象上执行它时,它似乎工作...

I've given that a try, and it seemed to work when I called lambda.Compile and executed it on a couple of sample Service objects...

这篇关于如何动态创建 Expression<Func<MyClass, bool>>表达式<Func<MyClass, string>中的谓词?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆