Синтаксис запросов LINQ — недооцененный инструмент для разработчиков C#

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Как многие уже наверняка знают, LINQ - встроенный в C# язык запросов, которые появился аж в 2007 году (.NET Framework 3.5) и существует он в виде двух реализаций: Query-синтаксис (синтаксис запросов) и Method-синтаксис (синтаксис методов). Несмотря на все возможности и достоинства синтаксиса запросов, он часто несправедливо игнорируется в пользу синтаксиса методов. И в этой статье я попытаюсь восстановить справедливость и на практических примерах покажу преимущества query-синтаксиса и его полезность для опытных разработчиков на C#.

Обзор Query-синтаксиса

По стилю и читабельности Query-синтаксис очень напоминает SQL. Он предоставляет собой декларативный способ работы с данными и является довольно выразительным и прямолинейным. Рассмотрим на примере интернет-магазина с товарами (Products).

Предположим, у нас есть список товаров, и мы хотим получить все с ценой выше 50.

class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

List<Product> products = new List<Product>
{
    new Product { Id = 1, Name = "Ноутбук", Price = 1200 },
    new Product { Id = 2, Name = "Клавиатура", Price = 80 },
    new Product { Id = 3, Name = "Мышь", Price = 30 },
    new Product { Id = 4, Name = "Монитор", Price = 300 }
};

Вот как будет выглядеть эта выборка с использованием синтаксиса запросов:

var expensiveProducts = from product in products
                        where product.Price > 50
                        select product;

А теперь сделаем то же самое, но синтаксисом методов:

var expensiveProducts = products.Where(p => p.Price > 50);

Как видно, первый вариант несколько более многословный, однако, он не заставляет людей задумываться что же это за переменная p, как это происходит во втором варианте.Ну и для начинающих программистов, не особо знакомых с лямбда выражениями, Query синтаксис пониматься будет нааамного проще.

Однако, этот пример довольно спорный, поэтому давайте посмотрим на примеры, где более явно видны преимущества использования синтаксиса запросов.

Сложные запросы и несколько источников данных

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

Предположим, у нас есть два списка: один для продуктов и другой для категорий продуктов. Мы хотим получить все продукты с соответствующими названиями категорий и ценами выше 50.

class Category
{
    public int Id { get; set; }
    public string Name { get; set; }
}

List<Category> categories = new List<Category>
{
    new Category { Id = 1, Name = "Электроника" },
    new Category { Id = 2, Name = "Аксессуары" }
};

Вот как мы можем сделать это с использованием синтаксиса запросов:

var result = from product in products
             join category in categories on product.CategoryId equals category.Id
             where product.Price > 50
             select new { 
                ProductName = product.Name,
                CategoryName = category.Name,
                Price = product.Price 
             };

Опять же, многословно, но вполне читабельно. А теперь давайте сравним это с синтаксисом методов:

var result = products
    .Where(p => p.Price > 50)
    .Join(categories, 
          p => p.CategoryId, 
          c => c.Id, 
          (p, c) => new { 
            ProductName = p.Name,
            CategoryName = c.Name,
            Price = p.Price 
          });

И это были только две коллекции, а лично мне уже приходится намного сильнее напрягать мозг, чтобы разобраться что же это за p, c, и что вообще здесь происходит. А теперь давайте рассмотрим следующий пример.

Группировка и агрегация данных

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

var groupedProducts = from product in products
                      join category in categories on product.CategoryId equals category.Id
                      group product by category.Name into productGroup
                      select new
                      {
                          CategoryName = productGroup.Key,
                          AveragePrice = productGroup.Average(p => p.Price)
                      };

Да, появилась новая абстракция - productGroup, однако, код остается вполне читабельным и понятным. Чего сказать о синтаксисе методов я уже не могу:

var groupedProducts = products
    .Join(categories, 
          p => p.CategoryId, 
          c => c.Id, 
          (p, c) => new { Product = p, Category = c })
    .GroupBy(pc => pc.Category.Name, pc => pc.Product)
    .Select(g => new { 
          CategoryName = g.Key,
          AveragePrice = g.Average(p => p.Price) 
    });

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

Комбинирование синтаксиса запросов и синтаксиса методов

Стоит отметить, что C# не накладывает на нас никакие ограничения по использованию только одного из этих синтаксисов, то есть мы можем легко (шутка) комбинировать Query-синтаксис и Method-синтаксис, чтобы использовать преимущества обоих подходов. Это может привести к более читабельному и удобному для поддержки коду в некоторых сценариях, но никаких гарантий я вам здесь не даю, действуйте на свой страх и риск.

Предположим, мы хотим получить категории со средней ценой продуктов выше 100. Так, используя комбинацию синтаксисов, мы можем получить вполне себе милого Франкенштейна:

var filteredGroups = (from product in products
                      join category in categories on product.CategoryId equals category.Id
                      group product by category.Name into productGroup
                      select new
                      {
                          CategoryName = productGroup.Key,
                          AveragePrice = productGroup.Average(p => p.Price)
                      })
                      .Where(group => group.AveragePrice > 100);

Заключение

Query-синтаксис - это мощный и выразительный инструмент, которым C# разработчики не должны пренебрегать при работе со сложными запросами, несколькими источниками данных и задачами связанными с агрегацией данных. И если вы хотите научиться самостоятельно так же лихо использовать синтаксис запросов, наряду с синтаксисом методов и их комбинацией, чтобы писать более удобный для поддержки и понятный код, то приглашаю вас на курс C# Developer. Professional. Для ознакомления с форматом обучения и знакомства с преподавателями приглашаю вас на бесплатный урок курса, где разработаем многопоточный сервер приложений с минимумом примитивов синхронизации. Рассмотрим вопросы синхронизации, масштабируемости приложения, обработку входящих сообщений, вопросы реализации длительных операций.

  • Зарегистрироваться на бесплатный урок

Источник: https://habr.com/ru/company/otus/blog/723438/


Интересные статьи

Интересные статьи

Всем привет! Меня зовут Максим Брежнев, я инженер нагрузочного тестирования на проекте Сбера. В этой статье я расскажу вам об инструментах нагрузочного тестирования, применяемых в финансово-техническо...
Итератор (от англ. iterator ― перечислитель) — интерфейс, предоставляющий доступ к элементам коллекции (массива или контейнера) и навигацию по ним. В различных системах итераторы могу...
Тоталитаризм и диктатура имели место в любой исторический промежуток, о котором знает современная наука. Однако человек склонен к вольномыслию и недовольству всем, что эт...
Недавно мы опубликовали перевод статьи про полезные расширения VS Code для Python-разработчиков. Настала очередь JavaScript! В прошлый раз читатели делились своими фаворитами в коммен...
Подборка утилит, литературы и фреймворков, которые помогут разобраться в требованиях регламента и подскажут, как им соответствовать. Под катом — бесплатные продукты от стартапа Algolia, сервисы к...