Есть один способ сделать это, который включает использование деревьев выражений. Таким образом, вы сами создаете логическое выражение. Сложность в том, что вам нужно перебазировать параметры, потому что в противном случае оно будет ссылаться на исходное лямбда-выражение. Ниже приведен пример:
static void Main(string[] args)
{
var source = new List<int> { 1, 2, 3 };
var any = new List<Expression<Func<int, bool>>>();
any.Add(x => x == 1);
any.Add(x => x == 3);
foreach (var item in source.AsQueryable().WhereDisjunction(any))
{
Console.WriteLine(item);
}
}
class RewriteSingleParameterUsage : ExpressionVisitor
{
public ParameterExpression Parameter { get; set; }
protected override Expression VisitParameter(ParameterExpression node)
{
return Parameter;
}
}
public static IQueryable<T> WhereDisjunction<T>(this IQueryable<T> source, IList<Expression<Func<T, bool>>> any)
{
switch (any.Count)
{
case 0: return source;
case 1: return source.Where(any[0]);
default:
var p = Expression.Parameter(any[0].Parameters[0].Type, any[0].Parameters[0].Name);
var rw = new RewriteSingleParameterUsage { Parameter = p };
var expr = rw.Visit(any[0].Body);
for (int i = 1; i < any.Count; i++)
{
expr = Expression.Or(expr, rw.Visit(any[i].Body));
}
return source.Where(Expression.Lambda<Func<T, bool>>(expr, p));
}
}
В приведенном выше примере я очень резок, я эффективно заменяю любой параметр этим единственным новым параметром, который используется для создания нового выражения. Однако, учитывая сигнатуру этого метода расширения, на самом деле не должно быть возможности вызывать этот метод с параметрами, которые могли бы вызвать ошибку. Однако это будет проблемой, если вы задействуете более одного параметра.