在表达式主体中替换参数名称 [英] Replacing the parameter name in the Body of an Expression
问题描述
我正在尝试根据规范对象动态构建表达式.
I'm trying to dynamically build up expressions based on a Specification object.
我创建了一个ExpressionHelper类,该类具有如下私有表达式:
I've created an ExpressionHelper class that has a private Expression like so:
private Expression<Func<T, bool>> expression;
public ExpressionHelper()
{
expression = (Expression<Func<T, bool>>)(a => true);
}
然后是一些简单的方法,如下所示:
And then some easy methods as follows:
public void And(Expression<Func<T,bool>> exp);
我正在为And方法的主体苦苦挣扎.我基本上想从exp
中剥离主体,将所有参数替换为expression
中的参数,然后将其与AndAlso一起附加到expression
主体的末尾.
I'm struggling with the body of the And method. I basically want to rip the body out of exp
, replace all the parameters with those in expression
and then append it to the end of the expression
body as and AndAlso.
我已经做到了:
var newBody = Expression.And(expression.Body,exp.Body);
expression = expression.Update(newBody, expression.Parameters);
但这最终使我的表情看起来像这样:
But that ends up with my expression looking like this:
{ a => e.IsActive && e.IsManaged }
有没有更简单的方法可以做到这一点?或者我该如何剔除那些e并用a代替?
Is there a simpler way to do this? Or how can I rip out those e's and replace them with a's?
推荐答案
这里最简单的方法是Expression.Invoke
,例如:
The simplest approach here is Expression.Invoke
, for example:
public static Expression<Func<T, bool>> AndAlso<T>(
Expression<Func<T, bool>> x, Expression<Func<T, bool>> y)
{
return Expression.Lambda<Func<T, bool>>(
Expression.AndAlso(x.Body, Expression.Invoke(y, x.Parameters)),
x.Parameters);
}
这对于LINQ-to-Objects和LINQ-to-SQL很好,但是EF不支持.遗憾的是,对于EF,您需要使用一个访问者来重写树.
This works fine for LINQ-to-Objects and LINQ-to-SQL, but isn't supported by EF. For EF you'll need to use a visitor to rewrite the tree, sadly.
使用以下代码:在c#中组合两个lambda表达式
public static Expression<Func<T, bool>> AndAlso<T>(
Expression<Func<T, bool>> x, Expression<Func<T, bool>> y)
{
var newY = new ExpressionRewriter().Subst(y.Parameters[0], x.Parameters[0]).Inline().Apply(y.Body);
return Expression.Lambda<Func<T, bool>>(
Expression.AndAlso(x.Body, newY),
x.Parameters);
}
或者在.NET 4.0中,使用ExpressionVisitor
:
Or in .NET 4.0, using ExpressionVisitor
:
class ParameterVisitor : ExpressionVisitor
{
private readonly ReadOnlyCollection<ParameterExpression> from, to;
public ParameterVisitor(
ReadOnlyCollection<ParameterExpression> from,
ReadOnlyCollection<ParameterExpression> to)
{
if(from == null) throw new ArgumentNullException("from");
if(to == null) throw new ArgumentNullException("to");
if(from.Count != to.Count) throw new InvalidOperationException(
"Parameter lengths must match");
this.from = from;
this.to = to;
}
protected override Expression VisitParameter(ParameterExpression node)
{
for (int i = 0; i < from.Count; i++)
{
if (node == from[i]) return to[i];
}
return node;
}
}
public static Expression<Func<T, bool>> AndAlso<T>(
Expression<Func<T, bool>> x, Expression<Func<T, bool>> y)
{
var newY = new ParameterVisitor(y.Parameters, x.Parameters)
.VisitAndConvert(y.Body, "AndAlso");
return Expression.Lambda<Func<T, bool>>(
Expression.AndAlso(x.Body, newY),
x.Parameters);
}
这篇关于在表达式主体中替换参数名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!