c# - 未定义表达式参数

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

我正在尝试对列表执行查询以使用代码中其他地方设置的表达式立即给出结果,而第二个线程关闭并使用它从 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>>)

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

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

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 参数并自行解析,这表明它们具有更广泛的可接受输入范围。

关于c# - 未定义表达式参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50964519/

相关文章:

c# - 无法从 Win7 x64 上的 32 位进程启动屏幕键盘 (osk.exe)

c# - 只有 Microsoft .NET 堆积柱形图控件中的第一个系列才能正确显示工具提示

linq - Entity Framework 3.5 - 如何加载子项

c# linq nested "conditional/composite"分组

LINQ 动态表达式 API,与 DBNull.Value 比较的谓词

c# - 替换表达式树中的类型

compiler-errors - Java中的范围检查编译困难

c# - 如何以编程方式创建新的本地 SQL Server 实例?

c# - 如何将 "|"字符设置为文本框的最后一个位置?

c# - 在 LINQ 中使用条件