8

我正在尝试将静态函数写入或两个表达式,但收到以下错误:

参数“项目”不在范围内。

说明:执行当前 Web 请求期间发生未处理的异常。请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息。

异常详细信息:System.InvalidOperationException:参数“项目”不在范围内。

方法:

public static Expression<Func<T, bool>> OrExpressions(Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
{
    // Define the parameter to use
    var param = Expression.Parameter(typeof(T), "item");

    var filterExpression = Expression.Lambda<Func<T, bool>>
         (Expression.Or(
             left.Body,
             right.Body
          ), param);
    // Build the expression and return it
    return (filterExpression);
}

编辑:添加更多信息

or'd 的表达式来自下面的方法,执行得很好。如果有更好的方法或结果我全神贯注。另外,我不知道有多少人被提前或被淘汰了。

public static Expression<Func<T, bool>> FilterExpression(string filterBy, object Value, FilterBinaryExpression binaryExpression)
{
    // Define the parameter to use
    var param = Expression.Parameter(typeof(T), "item");

    // Filter expression on the value
    switch (binaryExpression)
    {
        case FilterBinaryExpression.Equal:
            {
                // Build an expression for "Is the parameter equal to the value" by employing reflection
                var filterExpression = Expression.Lambda<Func<T, bool>>
                    (Expression.Equal(
                        Expression.Convert(Expression.Property(param, filterBy), typeof(TVal)),
                        Expression.Constant(Value)
                     ),
                    param);
                // Build the expression and return it
                return (filterExpression);
            }

编辑:添加更多信息

或者,有没有更好的方法来做一个或?目前,.Where(constraint) 在约束类型为 Expression> 的情况下工作得很好。我该怎么做 where(constraint1 or constraint2) (到约束 n'th)

提前致谢!

4

5 回答 5

9

问题是您在 OrExpressions 方法中创建的表达式重用了两个表达式的主体。这些主体将包含对它们自己的 ParameterExpression 的引用,该 ParameterExpression 已在 FilterExpression 中定义。

解决方法是重写左右部分以使用新的 ParameterExpression。或者传递原始的 ParameterExpression。并不是因为两个ParameterExpression同名就代表同一个参数。

于 2009-01-04T22:23:03.240 回答
5

正如已经建议的那样,在这里您可以找到这个非常好的(工作)代码

public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
    var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
    return Expression.Lambda<Func<T, bool>>(Expression.Or(expr1.Body, invokedExpr), expr1.Parameters);
}

您可以适应您的需求,并且与 LINQ 无关(恕我直言)。

于 2009-01-05T13:46:12.287 回答
3

我不确定这里的正确术语,但基本上表达式参数是不等价的,即使它们具有相同的名称。

这意味着

var param1 = Expression.Parameter(typeof(T), "item");
var param2 = Expression.Parameter(typeof(T), "item");

param1 != param2

如果在表达式中使用 param1 和 param2 将不是同一个东西。

处理这个问题的最佳方法是为您的表达式预先创建一个参数,然后将其传递给所有需要该参数的辅助函数。

编辑:另外,如果您尝试在 LINQ 中动态组合 where 子句,您可以尝试PredicateBuilder

于 2009-01-04T22:27:45.760 回答
2

对于那些通过搜索引擎找到此页面并打算使用Ben&Joe Albahari 的 PredicateBuilder 的人,请注意,因为它不适用于 Entity Framework

试试这个固定版本

于 2012-09-25T16:38:30.493 回答
1

我也想到了 Fabrizio 的解决方案,但由于我试图组合两个将作为 linq 2 sql 查询执行的表达式,我认为它会在内存中执行,而不是在 sql 服务器中执行。

我被写了——Linq-To-Sql 识别出调用是一个 lambda 表达式,因此仍然会产生优化的 sql。

于 2010-03-11T21:49:21.790 回答