Стандартные операторы запроса с LINQ - Преобразования и кванторы

ОГЛАВЛЕНИЕ

Преобразования и кванторы

Если нужно определить, присутствует ли то или иное значение в последовательности, можно использовать стандартный оператор Any. Кванторы (Any, All, Contains) позволяют просмотреть последовательность элементов и определить, соответствует она условиям лямбда-выражения или нет. Их удобно использовать, если, к примеру, нужно определить, существует ли клиент, проживающий по указанному адресу, в одной стране живут клиенты или нет, и так далее.

Запрос LINQ, приведенный ниже, позволяет проверить, все ли британские подданные из числа клиентов компании живут в Лондоне. Здесь используется квантор All и лямбда-выражение, определяющее, указан Лондон в качестве города проживания или нет. Если все элементы последовательности соответствуют этому критерию, то оператор All возвращает значение true:

using (Entities entities = new Entities())
{
  bool allUKCustomerAreFromLondon = (from c in entities.Customers
  where c.Country == "UK"
  select c).All(
  c => c.City.Equals("London"));
  Console.WriteLine(allUKCustomerAreFromLondon ? "Yes" : "No");

Еще один пример: есть ли среди британских клиентов компании люди, живущие в городе Каус. В этом случае используется оператор Any:

using (Entities entities = new Entities())
{
  bool isOneUKCustomerFromCowes = (from c in entities.Customers
  where c.Country == "UK"
  select c).Any(
  c => c.City.Equals("Cowes"));
  Console.WriteLine(isOneUKCustomerFromCowes? "Yes" : "No");
}

Оператор Contains по принципу действия схож с оператором Any: он тоже позволяет определить, есть ли в последовательности указанный элемент. Разница в том, что оператор Any определяет, присутствует ли определенное значение в элементе последовательности, а оператор Contains — присутствует ли в последовательности экземпляр элемента. Например, прежде чем добавить объект в последовательность, можно проверить, нет ли его там уже. На рис. 2, показано, как это сделать.

Figure 2 Using Contains and Conversion

using (Entities entities = new Entities())
{
  Customers customerBSBEV = (from c in entities.Customers
  where c.CustomerID == "BSBEV"
  select c).First();

  var customersUK = from c in entities.Customers
  where c.Country == "UK"
  select c;

  bool isCustomerInSequence = customersUK.Contains(customerBSBEV);

  Console.WriteLine(isCustomerInSequence? "Yes" : "No");
}

Обратите внимание, что в этом примере сущность Customers мы получаем для клиента BSBEV. Затем мы получаем последовательность сущностей Customer, соответствующих клиентам, проживающим в Великобритании. И наконец, оператор Contains проверяет, есть ли в последовательности экземпляр, присвоенный в качестве значения переменной customerBSBEV.

Вариант использования оператора Contains, показанный на рис. 2, применим тогда, когда наверняка известно, что объекты можно будет сравнить на основании экземпляров. А что если проверку нужно провести на основании логической идентификации? Оператор Contains позволяет передать объект, реализуя интерфейс IEqualityComparer<T>. Если оператор Contains должен работать на основании идентификатора клиента, код, приведенный на рис. 2, можно переписать следующим образом:

using (Entities entities = new Entities())
{
  ...

  bool isCustomerInSequence = customersUK.Contains(customerBSBEV,
  new CustomerComparer());

  Console.WriteLine(isCustomerInSequence? "Yes" : "No");
 } 

Элемент CustomerComparer определяется так:

private class CustomerComparer : IEqualityComparer<Customers>
{
  public bool Equals(Customers x, Customers y) {
  if (x == null || y == null)
  return false;
  return x.CustomerID.Equals(y.CustomerID);
  }

  ...

Выводы

Существует множество стандартных операторов, используемых в качестве методов расширения классов последовательностей Enumerable и Queryable. Они позволяют расширить возможности LINQ. Мы наглядно продемонстрировали, насколько большое количество средств, появившихся в платформе .NET Framework 3.5 (в их числе лямбда-выражения, LINQ, Entity Framework, неявно типизированные переменные), помогает повысить надежность кода и упростить логику приложения.

Джон Папа (John Papa) — старший консультант по технологии .NET в компании ASPSOFT (aspsoft.com) и страстный поклонник бейсбола, который почти все летние вечера проводит, болея за «Янки» со своим семейством и верным псом Кади. Джон, имея звание MVP по C#, является автором нескольких книг технологиям доступа к данным. Он также является спикерм INETA.