表达式参数未定义

时间:2018-06-21 09:02:04

标签: c# linq expression expression-trees linq-expressions

我正在尝试使用在代码中其他位置设置的表达式对列表进行查询以给出立即结果,而第二个线程关闭并使用它从Linq中的数据库中获取完整的结果集查询。

我知道表达式本身是可以的,就像我通过电线将其发送到服务器端并将其应用于IQueriable一样,它将可以正常工作。但是,在客户端应用时,会产生以下错误:

  

System.InvalidOperationException:从范围”引用的类型为'MissionControlSuite.Shared.Interface.Model.IBox'的'变量'item',但未定义'

执行过滤的此代码:

public abstract class GridWithPaging<T> where T : class
{
    List<T> _items

    public Expression<Func<T, bool>> Filter { get; set; }
    public ObservableCollection<IGridFilter<T>> Filters { get; set; }

    // more code skipped for breveity

    public void FiltersChanged(object sender, EventArgs e)
    {
        Expression<Func<T, bool>> combined = item => true;
        foreach (var filter in Filters)
            combined = Expression.Lambda<Func<T, bool>>(
                Expression.AndAlso(filter.Expression.Body, combined.Body),
                combined.Parameters.Single());

        Filter = combined;
        NotifyPropertyChanged("Filter");
    }

    public void AddFilter(IGridFilter<T> filter)
    {
        Filters.Add(filter);
        NotifyPropertyChanged("Filters");
    }

    private void DoFiltering(int start)
    {
        var newView = _items.Skip(start);
        if(Filter != null)
            newView = newView.AsQueryable().Where(Filter);

        //some more code that acts on the filtered list
    }
}

该表达式在其他位置设置如下:

Expression<Func<IBox, bool>> expression = item => item.BoxId.Contains(v);

var filter = new GridFilter<IBox>()
{
    Name = string.Format("{0} contains {1}", Property, Value),
    Expression = expression
};

Grid.AddFilter(filter);

1 个答案:

答案 0 :(得分:1)

此答案将帮助您:Combining two expressions (Expression<Func<T, bool>>)

总结:问题在于,尽管参数具有相同的名称,但它们与comment to that answer中包含的ParameterExpression实例不同。

解决方案是使用访客(从链接的帖子复制过来的代码):

public static Expression<Func<T, bool>> AndAlso<T>(
    this Expression<Func<T, bool>> expr1,
    Expression<Func<T, bool>> expr2)
{
    var parameter = Expression.Parameter(typeof (T));

    var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
    var left = leftVisitor.Visit(expr1.Body);

    var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
    var right = rightVisitor.Visit(expr2.Body);

    return Expression.Lambda<Func<T, bool>>(
        Expression.AndAlso(left, right), parameter);
}



private class ReplaceExpressionVisitor
    : ExpressionVisitor
{
    private readonly Expression _oldValue;
    private readonly Expression _newValue;

    public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
    {
        _oldValue = oldValue;
        _newValue = newValue;
    }

    public override Expression Visit(Expression node)
    {
        if (node == _oldValue)
            return _newValue;
        return base.Visit(node);
    }
}

另外请注意:ORM提供程序(或您使用的另一个IQueryable)可能有效,因为它直接将其转换为文本,而执行(Invoke ing)此LambdaExpression会导致错误,因为它更加严格,在某种方式。一些IQueryable还可以接受简单的string参数并自行解析,这表明它们具有更广泛的可接受输入。