Построение LINQ-запроса программно без хитрых локальных переменных - PullRequest
12 голосов
/ 10 октября 2008

Предположим, что мои объекты находятся в идеальном рабочем состоянии (т. Е. TDD заставляет меня думать, что они работают).

У меня есть список, который я создаю следующим образом (за исключением правильного отступа):

var result = from v in vendors
             from p in v.Products
             orderby p.Name
             select p;

Это работает - я получаю все товары от всех поставщиков.

Теперь у меня есть список условий, созданный пользователем во время выполнения. Давайте применим их:

foreach (Attribute a in requiredAttributes)
{
    result = result.Where(p => p.Attributes.Contains(a));
}

Это может быть примитивно, но я думал, что это сработает. Однако после завершения этого цикла foreach при перечислении «результата» он будет содержать все продукты, имеющие атрибут LAST коллекции requiredAttributes в свойстве Attributes (также коллекции).

Для меня это пахнет так, как будто "а" где-то перезаписывается при каждом путешествии по циклу, и применяется только последнее.

Если не считать написания какого-либо метода расширения для IEnumerable, называемого ContainsAll (IEnumerable), или чего-то в этом роде, как я могу достичь того, чего хочу, что по сути является логическим И, давая мне только те продукты, которые имеют ВСЕ обязательные атрибуты?

Ответы [ 3 ]

19 голосов
/ 10 октября 2008

(отредактировано для ясности.)

Проблема заключается в цикле foreach, а также в том факте, что переменная «a» захватывается и затем изменяется каждый раз. Вот модификация, которая будет работать, эффективно вводя «новую» переменную для каждой итерации цикла и захватывая эту новую переменную.

foreach (Attribute a in requiredAttributes)
{
    Attribute copy = a;
    result = result.Where(p => p.Attributes.Contains(copy));
}

Решение Омера более чистое, если вы можете его использовать, но это может помочь, если ваш реальный код на самом деле более сложный:)

РЕДАКТИРОВАТЬ: подробнее о проблеме в рассказывается в этой статье - прокрутите вниз до пункта «Сравнение стратегий захвата: сложность и мощность».

7 голосов
/ 10 октября 2008
var result = from v in vendors
             from p in v.Products
             where requiredAttributes.All(a => p.Attributes.Contains(a))
             orderby p.Name
             select p;

НТН.

5 голосов
/ 10 октября 2008

Я не закодировал, но изменил

foreach (Attribute a in requiredAttributes){    
    result = result.Where(p => p.Attributes.Contains(a));
}

до

foreach (Attribute a in requiredAttributes){    
    Attribute b = a;
    result = result.Where(p => p.Attributes.Contains(b));
}

я тоже должен это исправить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...