как вызвать метод .Where () в linq более одного раза, чтобы действовать как OR (||) - PullRequest
1 голос
/ 26 декабря 2011


Я пытаюсь создать класс, который позволяет мне настраивать запрос LINQ во время выполнения с помощью метода .Where (), после завершения моего класса и во время тестирования результат оказался не таким, как я ожидал, поэтому у меня возникла проблема, и я решил, что мне нужно чтобы вызвать несколько раз .Where () метод, и он должен действовать как ИЛИ || не как AND &&
Пример:

class Program
{

    private static string WhereTest()
    {
        string result = "";

        // List
        string[] lst = { "Sa", "Su", "Mo", "Tu", "We", "Th", "Fr" };

        // test 1
        var q1 = from l in lst
                 where l.StartsWith("S") && l.EndsWith("u")
                 select l;
        result = "1st query count: " + q1.Count() 
            + "\n----------------- \nItems: \n------- \n";
        foreach (var item in q1.ToList())
        {
            result += item + "\n";
        }
        result += "\n";
        result += "\n";

        // test 2
        var q2 = from l in lst
                 where l.StartsWith("S") || l.EndsWith("u")
                 select l;
        result += "2nd query count: " + q2.Count() 
            + "\n----------------- \nItems: \n------- \n";
        foreach (var item in q2.ToList())
        {
            result += item + "\n";
        }
        result += "\n";
        result += "\n";

        // test 3
        var q3 = from l in lst
                 select l;
        if (true)
            q3 = q3.Where(l => l.StartsWith("S"));
        if (true)
            q3 = q3.Where(l => l.EndsWith("u"));

        result += "3rd query count: " + q3.Count() 
            + "\n----------------- \nItems: \n------- \n";
        foreach (var item in q3.ToList())
        {
            result += item + "\n";
        }
        result += "\n";
        result += "\n";


        return result;
    }
    static void Main(string[] args)
    {
        Console.WriteLine(WhereTest());
    }
}


Результат:

            1st query count: 1
            -----------------
            Items:
            -------
            Su


            2nd query count: 3
            -----------------
            Items:
            -------
            Sa
            Su
            Tu


            3rd query count: 1
            -----------------
            Items:
            -------
            Su

В моем примере q3 возвращает тот же результат, что и q1
Поэтому мне нужно знать, смогу ли я заставить q3 вернуть мне тот же результат, что и в q2.
Привет

Ответы [ 3 ]

2 голосов
/ 26 декабря 2011

Посмотрите на System.Linq.Expressions

// List
string[] lst = { "Sa", "Su", "Mo", "Tu", "We", "Th", "Fr" };

Expression<Func<string, bool>> expr1 = t => t.StartsWith("S");
Expression<Func<string, bool>> expr2 = t => t.EndsWith("u");

var filter = new List<Expression>();

if (true)
{
    filter.Add(expr1);
}

if (true)
{
    filter.Add(expr2);
}

var input = Expression.Parameter(typeof(string), "input");
var result = Expression.Parameter(typeof(bool), "result");

var blockExpression = Expression.Block(
    new[] { result },
    Expression.Assign(result, Expression.Or(Expression.Invoke(expr1, input), Expression.Invoke(expr2, input)))

    );

var x = Expression.Lambda<Func<string, bool>>(blockExpression, new[] { input });

var func = x.Compile();

var res = lst.Where(func);


foreach (var re in res)
{
    Console.WriteLine(re);
}
2 голосов
/ 26 декабря 2011

Для LINQ to SQL или других провайдеров, основанных на запросах, PredicateBuilder является решением.Он не позволяет вам вызывать Where несколько раз, но позволяет динамически создавать предикат с использованием нескольких вызовов.

Для LINQ to Objects вы можете создать собственный эквивалент PredicateBuilder, используя делегаты вместодеревья выражений , как показано в этом ответе .Просто для того, чтобы этот ответ был завершен сам по себе, вот тот же код снова:

public static class DelegatePredicateBuilder
{
  public static Func<T, bool> True<T>()  { return f => true;  }
  public static Func<T, bool> False<T>() { return f => false; }

  public static Func<T, bool> Or<T>(this Func<T, bool> expr1,
                                     Func<T, bool> expr2)
  {
      return t => expr1(t) || expr2(t);
  }

  public static Func<T, bool> And<T>(this Func<T, bool> expr1,
                                     Func<T, bool> expr2)
  {
      return t => expr1(t) && expr2(t);
  }
}

Таким образом, вы бы использовали что-то вроде:

var predicate = DelegatePredicateBuilder.False<string>();

if (someCondition)
{
    predicate = predicate.Or(l => l.StartsWith("S"));
}

if (someCondition)
{
    predicate = predicate.Or(l => l.EndsWith("u"));
}

query = query.Where(predicate);
2 голосов
/ 26 декабря 2011

вы можете сделать что-то вроде этого.

q3 = q3.Where(l => l.EndsWith("u") || l => l.StartsWith("S")); 

Если вы ищете динамический способ построения запроса, следующая ссылка имеет построитель предикатов, который вам поможет.

...