Expression.Or,参数'item'不在范围内

时间:2009-01-04 21:44:32

标签: c# linq expression-trees expression

我正在尝试为Or表达式写一个静态函数,但收到以下错误:

  

参数'item'不在范围内。

     

描述:未处理的异常   在执行期间发生   当前的网络请求。请查看   堆栈跟踪以获取更多信息   错误及其来源   代码。

     

异常详细信息:   System.InvalidOperationException:The   参数'item'不在范围内。

方法:

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);
}

修改:添加更多信息

正在或将来的表达式来自下面的方法,执行得很好。如果有更好的方法或结果我都是耳朵。另外,我不知道有多少人提前或正在等待。

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(约束)在约束为Expression&gt;类型的情况下工作得很好。我该怎么做(constraint1或constraint2)(到约束n'th)

提前致谢!

5 个答案:

答案 0 :(得分:9)

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

修复方法是重写左右部分以使用新的ParameterExpression。或者传递原始的ParameterExpression。这不是因为两个ParameterExpression具有相同的名称,它们代表相同的参数。

答案 1 :(得分:5)

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

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绑定(恕我直言)。

答案 2 :(得分:2)

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

这意味着

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

param1 != param2
如果在表达式中使用,

param1和param2将不会是同一个东西。

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

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

答案 3 :(得分:2)

对于那些通过搜索引擎找到此页面并将使用 Ben&amp; Joe Albahari的PredicateBuilder 的人,请注意,因为不适用于实体框架< /强>

请尝试this fixed version

答案 4 :(得分:1)

Fabrizio的解决方案也出现在我身上,但由于我试图将两个表达式组合起来,这些表达式将作为linq 2 sql查询执行,我认为它将在内存而不是sql server中执行。

我写了 - Linq-To-Sql认识到调用是lambda表达式,因此仍然会生成优化的sql。