Reputation: 10422
Assuming the following prefiltered IQueryable:
var query = items.Where(i => i.PropertyName == "Some property");
coming from a third party library, is it possible to either remove the Where clause completely, or replace it with:
.Where(i => i.PropertyName == null || i.PropertyName == "Some property")
I've seen mentions of being able to rewrite the IQueryable on the fly. Would this approach have any downsides? How would I go about doing it? Is there a better way?
Update
I've managed to cobble something together using ExpressionVisitor as suggested by Ivan:
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);
}
}
and:
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();
}
}
While this compiles fine, it throws "Lambda type parameter must be derived from System.Delegate" in the extension method.
Upvotes: 3
Views: 1316
Reputation: 10422
I've managed to put something together using ExpressionVisitor as suggested by Ivan:
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);
}
}
and:
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();
}
}
Upvotes: 3