我有一个集合List<List<object>>
,我需要根据List<object>
集合包含给定元素的过滤器来过滤掉它。我能够构建where子句,但是我得到以下异常:
类型&#39; System.InvalidOperationException&#39;的例外情况发生在System.Core.dll中但未在用户代码中处理 附加信息:变量&#39; x&#39;类型&#39; System.Collections.Generic.List`1 [System.Object]&#39;引用范围&#39;&#39;,但未定义
我发现了类似的问题,我明白问题所在,但我需要帮助找到解决方案。
这是我的代码:
protected override Expression<Func<List<object>, bool>> GetWhereClause()
{
var type = typeof(List<object>);
var parameterExpression = Expression.Parameter(type, "x");
Expression expressionBody = null;
if (Verified)
{
Expression<Func<List<object>, bool>> expression = x => x.Contains("Verified");
expressionBody = expression.Body;
}
if (GoodMatch)
{
Expression<Func<List<object>, bool>> expression = x => x.Contains("Good Match");
if (expressionBody != null)
expressionBody = Expression.Or(expressionBody, expression.Body);
else
expressionBody = expression.Body;
}
//More conditions here
if (expressionBody != null)
{
var whereClauseExp = Expression.Lambda<Func<List<object>, bool>>(expressionBody, parameterExpression);
return whereClauseExp;
}
return null;
}
现在,这个方法生成了所需的where子句,但是当我尝试应用它时,我得到了提到的异常。
if (whereClause != null)
{
items = items.Where(whereClause.Compile());
//
}
答案 0 :(得分:1)
我有一个类似的用例需要动态where子句并使用Predicate Builder
使用它,您可以执行以下操作:*
private Expression<Func<List<T>, bool>> GetWhereClause<T>(T itemToFind){
var predicate = PredicateBuilder.False<List<T>>();
if(Verified) {
predicate = predicate.And(p => p.Contains(itemToFind));
}
if(GoodMatch) {
predicate = predicate.Or(p => p.Contains(itemToFind));
}
return predicate;
}
答案 1 :(得分:0)
您不能在新表达式中“按原样”使用其他表达式中的参数。当你这样做时:
Expression<Func<List<object>, bool>> expression = x => x.Contains("Verified");
expressionBody = expression.Body;
然后你只需要在正文中定义内联参数x。现在这个参数不是你以前定义为
的参数var parameterExpression = Expression.Parameter(type, "x");
即使他们都有名字x,这还不够。表达式树具有引用相等性。 因此,要使其工作,只需使用访问者,这将取代您的参数。创建访问者:
public class ParameterUpdateVisitor : ExpressionVisitor
{
private ParameterExpression _parameter;
public ParameterUpdateVisitor(ParameterExpression parameter)
{
_parameter = parameter;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return _parameter;
}
}
然后在你的代码中使用它:
Expression<Func<List<object>, bool>> expression = x => x.Contains("Verified");
var visitor = new ParameterUpdateVisitor(parameterExpression);
expressionBody = visitor.Visit(expression.Body);
当然这适用于来自另一个表达式树的每个部分。
请注意!!!这个访客是额外的简化,只是为了你的例子。如果您的表达式可能包含具有自己参数的方法,那么请确保仅替换您想要的参数! 例如。它不适用于:
Expression<Func<List<object>, bool>> expression = x => x.Select(o => o.ToString()).Contains("Verified");
因为这位访客也将取代'o'。如果你有这种情况,那么也要在构造函数中传入你想要替换的参数(例如x,即expression.Parameters.First()),并且只在node == myOldParameter中替换覆盖的方法。
顺便说一句:如果你最后编译那个东西,为什么还需要表达式树呢?