如何解决将两个表达式Expression <Func <T,bool >>组合成一个表达式
我要编译两个表达式:
public Expression<Func<AnyType,bool>> BuildExpression(int id,string filtreA,string filtreB)
{
Expression<Func<AnyType,bool>> extraExpression = null;
Expression<Func<AnyType,bool>> expression = null;
expression = a => a.ID == id;
var fullExpression = expression.Body;
if (!String.IsNullOrEmpty(filtreA))
{
extraExpression = a => a.TYPE == filtreA;
fullExpression = Expression.AndAlso(fullExpression,extraExpression.Body);
}
if (!String.IsNullOrEmpty(filtreB))
{
extraExpression = a => a.TYPE == filtreB;
fullExpression = Expression.AndAlso(fullExpression,extraExpression.Body);
}
expression = Expression.Lambda<Func<AnyType,bool>>(fullExpression,expression.Parameters[0]);
}
return expression;
}
//I want my final expression to be a.ID == id && a.TYPE == filtreB for example
问题是我得到以下错误: system.invalidOperationException。 Leparamètre'a'n'est pas dans laportée。。仅当输入我的一个ifs时才会发生。
有人知道我该如何处理吗?谢谢
ps:我的问题与本文相似,但似乎该解决方案不再起作用:Combining two expressions (Expression<Func<T,bool>>)
解决方法
您错过了参数替换。这对访客来说是一个棘手的问题。 为了简化您的生活,我建议使用流行的库LINQKit 并重写您的表情构建。
public Expression<Func<AnyType,bool>> BuildExpression(int id,string filtreA,string filtreB)
{
var predicate = PredicateBuilder.New<AnyType>(true);
predicate = predicate.And(a => a.ID == id);
if (!string.IsNullOrEmpty(filtreA))
{
predicate = predicate.And(a => a.TYPE == filtreA);
}
if (!string.IsNullOrEmpty(filtreB))
{
predicate = predicate.And(a => a.TYPE == filtreB);
}
return predicate;
}
,
每个参数都是一个不同的ParameterExpression
实例。如果您为每个表达式定义了不同的参数名称,此问题将更加明显;
expression = a => a.ID == id;
// ...
extraExpression = b => b.TYPE == filtreA;
// ...
extraExpression = c => c.TYPE == filtreB;
请注意,实体框架核心2.1及更早版本并不关心您的参数是否不同,并且似乎会通过.Invoke
操作进行查找。但是从版本3开始,使用表达式编译器的内部重写,不支持这两种格式。因此,为什么以前的示例可能不再起作用。
交换参数表达式的表达式访问者并不复杂;
public class MapParameters:ExpressionVisitor
{
private readonly Dictionary<ParameterExpression,ParameterExpression> mapping;
public MapParameters(IEnumerable<ParameterExpression> before,IEnumerable<ParameterExpression> after)
{
this.mapping = new Dictionary<ParameterExpression,ParameterExpression>(
before
.Zip(after)
.Select(p => KeyValuePair.Create(p.First,p.Second))
);
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (mapping.TryGetValue(node,out var replace))
return replace;
return base.VisitParameter(node);
}
}
Expression.Lambda<Func<AnyType,bool>>(
Expression.AndAlso(
expression.Body,new MapParameters(
extraExpression.Parameters,expression.Parameters
).Visit(extraExpression.Body)
),expression.Parameters);
还请注意,如果您使用它为IQuerable<T>.Where(...)
构建单个表达式。您可以考虑两次调用.Where(...)
,这将获得相同的最终结果。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。