Я надеюсь, что кто-то еще может искать эту тему, как я, на самом деле, поэтому я хотел бы предложить следующую возможность.
С момента выпуска .NET 4.0 вы можете использовать встроенные посетители дерева выражений .
Вот пример, который реализует необходимую функциональность:
private class ExpressionConstantInjector<T, TConstant> : ExpressionVisitor
{
private readonly TConstant toInject;
private readonly ParameterExpression targetParam;
public EntityExpressionListInjector(TConstant toInject)
{
this.toInject = toInject;
targetParam = Expression.Parameter(typeof(T), "a");
}
public Expression<Func<T, bool>> Inject(Expression<Func<T, TConstant, bool>> source)
{
return (Expression<Func<T, bool>>) VisitLambda(source);
}
protected override Expression VisitLambda<T1>(Expression<T1> node)
{
return Expression.Lambda(Visit(node.Body), targetParam);
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type == typeof (TConstant))
return Expression.Constant(toInject);
return targetParam;
}
}
Использование:
Expression<Func<Entity, List<int>, bool>> expression = (e, ids) => ids.Contains(e.Id);
var filterExpression
= new ExpressionConstantInjector<Entity, List<int>>(new List<int>{1, 2, 3})
.Inject(expression);
// filterExpression is like a => (1, 2, 3).Contains(a.Id)
// filterExpression can be passed to EF IQueryables.
Это решение очень локальное, не очень многократно используемое, но довольно простое (нет).
Если честно, [].Contains(id)
- это единственный случай, который я проверял. Но я думаю, что это работает.