聚合 Linq 表达式:获取从范围引用的变量的异常
Aggregate Linq Expressions: getting an exception of variable referenced from scope
我有一个表达式列表,类型为:Expression<Func<Person, bool>>
,我想聚合它们,然后将聚合结果编译成一个 Func<Person, bool>
。我能够创建聚合表达式,但编译结果聚合表达式的部分抛出异常。任何帮助,将不胜感激。谢谢。
Expression<Func<Person, bool>> expr1 = x => x.Age > 10;
Expression<Func<Person, bool>> expr2 = x => x.LastName == "some firstname";
Expression<Func<Person, bool>> expr3 = x => x.FirstName == "some lastname";
Expression<Func<Person, bool>> expr4 = x => x.Initial == 'a';
Expression<Func<Person, bool>> expr5 = x => x.DateOfBirth == DateTime.Now;
Expression<Func<Person, bool>> expr6 = x => x.Height > 10;
var exprList = new List<Expression<Func<Person, bool>>>()
{
expr1, expr2, expr3, expr4, expr5
};
var list = exprList
.Select(x => x.Body)
.Aggregate(Expression.AndAlso);
// this works, apparently?!
var aggregatedExpression = Expression.Lambda<Func<Person, bool>>(list, Expression.Parameter(typeof(Person), "x"));
// fails here! it cannot compile
var result = aggregatedExpression.Compile();
这是例外情况:
Unhandled Exception: System.InvalidOperationException: variable 'x' of type 'TestAggregateExpression.Person' referenced from scope '', but it is not defined
at System.Linq.Expressions.Compiler.VariableBinder.Reference(ParameterExpression node, VariableStorageKind storage)
我相信您需要访问列表中的所有表达式并替换参数。使用这个助手:
internal sealed class ParameterReplacer : ExpressionVisitor
{
private readonly ParameterExpression _param;
private ParameterReplacer(ParameterExpression param)
{
_param = param;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return node.Type == _param.Type ?
base.VisitParameter(_param) : // replace
node; // ignore
}
public static T Replace<T>(ParameterExpression param, T exp) where T : Expression
{
return (T)new ParameterReplacer(param).Visit(exp);
}
}
用法:
var param = Expression.Parameter(typeof(Person), "x"); // I'd use 'p' by the way
exp = ParameterReplacer.Replace(param, exp);
你的情况:
var list = exprList.Select(x => x.Body)
.Select(exp => ParameterReplacer.Replace(param, exp))
.Aggregate(Expression.AndAlso);
我有一个表达式列表,类型为:Expression<Func<Person, bool>>
,我想聚合它们,然后将聚合结果编译成一个 Func<Person, bool>
。我能够创建聚合表达式,但编译结果聚合表达式的部分抛出异常。任何帮助,将不胜感激。谢谢。
Expression<Func<Person, bool>> expr1 = x => x.Age > 10;
Expression<Func<Person, bool>> expr2 = x => x.LastName == "some firstname";
Expression<Func<Person, bool>> expr3 = x => x.FirstName == "some lastname";
Expression<Func<Person, bool>> expr4 = x => x.Initial == 'a';
Expression<Func<Person, bool>> expr5 = x => x.DateOfBirth == DateTime.Now;
Expression<Func<Person, bool>> expr6 = x => x.Height > 10;
var exprList = new List<Expression<Func<Person, bool>>>()
{
expr1, expr2, expr3, expr4, expr5
};
var list = exprList
.Select(x => x.Body)
.Aggregate(Expression.AndAlso);
// this works, apparently?!
var aggregatedExpression = Expression.Lambda<Func<Person, bool>>(list, Expression.Parameter(typeof(Person), "x"));
// fails here! it cannot compile
var result = aggregatedExpression.Compile();
这是例外情况:
Unhandled Exception: System.InvalidOperationException: variable 'x' of type 'TestAggregateExpression.Person' referenced from scope '', but it is not defined
at System.Linq.Expressions.Compiler.VariableBinder.Reference(ParameterExpression node, VariableStorageKind storage)
我相信您需要访问列表中的所有表达式并替换参数。使用这个助手:
internal sealed class ParameterReplacer : ExpressionVisitor
{
private readonly ParameterExpression _param;
private ParameterReplacer(ParameterExpression param)
{
_param = param;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return node.Type == _param.Type ?
base.VisitParameter(_param) : // replace
node; // ignore
}
public static T Replace<T>(ParameterExpression param, T exp) where T : Expression
{
return (T)new ParameterReplacer(param).Visit(exp);
}
}
用法:
var param = Expression.Parameter(typeof(Person), "x"); // I'd use 'p' by the way
exp = ParameterReplacer.Replace(param, exp);
你的情况:
var list = exprList.Select(x => x.Body)
.Select(exp => ParameterReplacer.Replace(param, exp))
.Aggregate(Expression.AndAlso);