При использовании LINQ в чем разница между && и multiple where clauses?

Я новичок в LINQ и вчера обнаружил, что вы можете иметь несколько предложений, таких как:

var items = from object in objectList
where object.value1 < 100  
where object.value2 > 10  
select object;

Или вы можете написать:

var items = from object in objectList
where object.value1 < 100  
   && object.value2 > 10  
select object;

В чем разница между двумя?

Ответ 1

Первый будет переведен на:

objectList.Where(o => o.value1 < 100).Where(o=> o.value2 > 10)

а второй - в:

objectList.Where(o => o.value1 < 100 && o.value2 > 10)

Итак, в первом случае у вас будет первая отфильтрованная последовательность, которая будет отфильтрована снова (первая последовательность содержит все объекты со значением < 100, вторая из которых содержит все объекты со значением > 10 из первой последовательности), в то время как во втором вы будете делать то же самое сравнение в том же выражении labda. Это справедливо для Linq для объектов, для других поставщиков это зависит от того, как выполняется перевод выражения.

Ответ 2

Первый переводит на:

objectList.Where(o => o.value1 < 100)
          .Where(o => o.value2 > 10);

в то время как последнее получает вас:

objectList.Where(o => o.value1 < 100 && o.value2 > 10);       

Это функция то же самое, и, хотя вторая избавит вызов метода, разница в производительности незначительна. Используйте то, что более читаемо для вас.

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

Ответ 3

Отмеченный ответ немного неточен.

Как сказал @Philippe, первый будет переведен в:

objectList.Where(o => o.value1 < 100).Where(o=> o.value2 > 10)

а второй - в:

objectList.Where(o => o.value1 < 100 && o.value2 > 10)

Но Linq имеет небольшую оптимизацию для цепочечных вызовов Where.

Если вы проверите исходный код Linq's, вы увидите следующее:

class WhereEnumerableIterator<TSource> : Iterator<TSource>
{
    public override IEnumerable<TSource> Where(Func<TSource, bool> predicate)
    {
        return new WhereEnumerableIterator<TSource>(source, 
            CombinePredicates(this.predicate, predicate));
    }
}

То, что CombinePredicates делает, это объединение двух предикатов с && между ними:

static Func<TSource, bool> CombinePredicates<TSource>(Func<TSource, bool> predicate1,
    Func<TSource, bool> predicate2)
{
    return x => predicate1(x) && predicate2(x);
}

Итак, objectList.Where(X).Where(Y) эквивалентно objectList.Where(X && Y), за исключением времени создания запроса (что очень коротко) и вызова двух предикатов.

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

Ответ 4

Я просто профилирую его. Нет разницы в SQL-коде.

Ответ 5

На самом базовом уровне вы получаете две операции Where вместо одного. Использование Reflector - лучший способ изучить, что выходит на другой конец выражения запроса.

Независимо от того, оптимизируются ли они до одного и того же, зависит от фактического поставщика LINQ - ему нужно взять все дерево и преобразовать его в другой синтаксис. Для LINQ To Objects это не так.

С# в глубине хорошо дать вам понимание этой темы.

Ответ 6

Как об этом для ответа: с && вы не можете гарантировать, что оба выражения должны быть оценены (если первое условие является ложным, то второе не может быть оценено). С этими двумя предложениями вы можете. Не знаю, правда ли это, но это звучит хорошо для меня!

Ответ 7

При прочих равных условиях я бы выбрал версию condition1 && condition2 для удобства чтения кода.