如何在现有的IQueryable中移除或覆盖where子句

3
假设以下已经过预筛选的IQueryable:
var query = items.Where(i => i.PropertyName == "Some property");

来自第三方库,是否可能完全删除WHERE子句,或者用以下内容替换:

.Where(i => i.PropertyName == null || i.PropertyName == "Some property")

我看到过有人提到可以动态重写IQueryable。这种方法是否有任何缺点?我该如何操作?还有更好的方法吗?

更新:

我已经按照Ivan的建议使用ExpressionVisitor拼凑了一些东西:

public class WhereRemoveVisitor : ExpressionVisitor
{
    protected override Expression VisitMethodCall(MethodCallExpression node)
    {
        if (node.Method.Name == "Where" && node.Method.DeclaringType == typeof(Queryable))
            return node.Arguments[0];
        else
            return base.VisitMethodCall(node);
    }
}

并且:

public static class IQueryableExtensions
{
    public static IQueryable<T> RemoveWhere<T>(this IQueryable<T> expression)
    {
        return Expression.Lambda<IQueryable<T>>(new WhereRemoveVisitor().Visit(expression.Expression)).Compile();
    }
}

虽然这段代码可以编译通过,但在扩展方法中会抛出“Lambda类型参数必须派生自System.Delegate”的错误。


1
一旦您确定需要什么,就可以使用自定义的“ExpressionVisitor”来查找/替换/删除查询表达式树的部分。 - Ivan Stoev
1个回答

3
我已经按照Ivan的建议使用ExpressionVisitor组装了一些东西:
public class WhereRemoveVisitor : ExpressionVisitor
{
    protected override Expression VisitMethodCall(MethodCallExpression node)
    {
        if (node.Method.Name == "Where" && node.Method.DeclaringType == typeof(Queryable))
            return node.Arguments[0];
        else
            return base.VisitMethodCall(node);
    }
}

并且:

public static class IQueryableExtensions
{
    public static IQueryable<T> RemoveWhere<T>(this IQueryable<T> expression)
    {
        var delExpr = Expression.Lambda<Func<IQueryable<T>>>(new WhereRemoveVisitor().Visit(expression.Expression)).Compile();
        return delExpr();
    }
}

2
接近了。但是不要编译和调用,而是使用return query.Provider.CreateQuery<T>(new WhereRemoveVisitor().Visit(query.Expression)); :) - Ivan Stoev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接