未定义表达式参数

Expression parameter is not defined

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

我知道表达式本身没问题,因为当我通过网络将它发送到服务器端并将它应用于 IQueryable 时它就会起作用。但是,在客户端应用时会产生以下错误:

System.InvalidOperationException: 'variable 'item' of type 'MissionControlSuite.Shared.Interface.Model.IBox' referenced from scope '', but it is not defined'

执行过滤的代码:

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

这个答案对您有帮助:Combining two expressions (Expression<Func<T, bool>>)

总结一下:问题是参数虽然名称相同,但与 ParameterExpression 实例 不同 - 它包含在 comment to that answer.

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

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)可能有效,因为它直接将其转换为文本,而执行(Invokeing)此 LambdaExpression 会导致错误,因为它更多严格,在某种程度上。一些 IQueryable 也可以接受简单的 string 参数并自行解析,这应该表明它们具有更广泛的可接受输入范围。