Взгляните на предстоящие улучшения LINQ в .NET 6

.NET 6 Изучение

Когда в 2007 году была выпущена.NET Framework 3.5, в нее была включена новая функция, известная как Language Integrated Query, или сокращенно LINQ. LINQ позволяет разработчикам.NET писать эффективный код C # с использованием стрелочных функций для запроса коллекций объектов или даже баз данных с использованием таких библиотек, как Entity Framework Core.

Как и все, что есть в.NET, LINQ продолжает развиваться с течением времени. Предстоящий выпуск.NET 6 предлагает ряд действительно интересных функций, включая набор новых возможностей LINQ.

В этой статье мы кратко рассмотрим основные улучшения LINQ, которые скоро появятся у разработчиков.NET с.NET 6.

Чтобы использовать эти новые API-интерфейсы LINQ, вы должны быть на.NET 6 preview 6 или более поздней версии. Полный выпуск.NET 6 должен произойти в конце 2021 года, но если вы хотите поиграть с этими функциями раньше, вы можете загрузить официальную предварительную версию от Microsoft.

Разбивка

Разделение на части, вероятно, является самым большим дополнением к LINQ в.NET 6. Если вы похожи на меня, вам приходилось работать с большими коллекциями объектов раньше и вы хотели взять большую коллекцию и работать с ней небольшими страницами или «фрагментами». «Этой большой коллекции.

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

List<List<Movie>> pages = new List<List<Movie>>();

const int PAGE_SIZE = 5;

List<Movie> currentPage = null;
int spaceRemaining = 0;

foreach (Movie movie in movies) {
    // Check to see if we're at the start of a new page
    if (spaceRemaining <= 0) {
        // Move to a new page and add it to our list
        currentPage = new List<Movie>();
        pages.Add(currentPage);
        spaceRemaining = PAGE_SIZE;
    }

    // Add items to the current page and decrease the count allowable in this page
    currentPage.Add(movie);
    spaceRemaining--;
}

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

К счастью, в.NET 6 LINQ теперь поддерживает все это в одной строке кода C # с помощью своего Chunkметода:

const int PAGE_SIZE = 5;

IEnumerable<Movie[]> chunks = movies.Chunk(PAGE_SIZE);

Этот новый метод намного лаконичнее и проще в использовании, чем попытки написать и протестировать собственный код фрагментов в любое время, когда он вам понадобится. Я вижу, что эта функция невероятно полезна для людей, пытающихся создать, например, страничный API или какую-либо форму приложения для пакетной обработки.

Поддержка индекса для ElementAt

Следующая функция проще, но все же эффективна. Раньше, если вы хотели получить что-то из конца коллекции, вам нужно было вычислить длину коллекции, а затем получить элемент по этому индексу, при необходимости вычитая:

Movie lastMovie = movies.ElementAt(movies.Count() - 1);

В.NET 6 LINQ теперь позволяет использовать Indexперегрузку ElementAtметода следующим образом:

Movie lastMovie = movies.ElementAt(^1);

Индексы используются с.NET Core 3.0, но позволяют использовать простой синтаксис для захвата элементов, начиная с задней части коллекции.

Поддержка диапазона для Take

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

Movie middleMovies = movies.Take(6..10);

Этот код элегантно прост и пропускает до 6-го элемента, а затем захватывает следующие 4 записи. Другие выражения диапазона, такие как..3или, 5..также работают, что значительно расширяет ваши возможности захвата элементов из коллекций по определенным индексам.

3 параметра Zip Overload

Ранее LINQ предлагал разработчикам.NET Zipметод, который позволял бы им перечислять две коллекции параллельно:

string[] titles = { "A Tale of Two Variables", "The Heisenbug", "Pride, prejudice, and semicolons" };
string[] genres = { "Drama", "Horror", "Romance" };

foreach ((string title, string genre) in titles.Zip(genres)) {
    Console.WriteLine($"{title} is a {genre} film");
}

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

Чтобы удовлетворить эту потребность, LINQ теперь имеет дополнительную перегрузку, которая позволяет трем коллекциям работать в тандеме:

string[] titles = { "A Tale of Two Variables", "The Heisenbug", "Pride, prejudice, and semicolons" };
string[] genres = { "Drama", "Horror", "Romance" };
float[] ratings = { 5f, 3.5f, 4.5f };

foreach ((string title, string genre, float rating) in titles.Zip(genres, ratings)) {
    Console.WriteLine($"{title} is a {genre} film that got a rating of {rating}");
}

Параметры по умолчанию для общих методов

Вездесущие методы LINQ FirstOrDefault, SingleOrDefaultи LastOrDefaultявляются основой разработки LINQ на C #.

Проще говоря, эти методы будут смотреть на коллекцию и возвращать совпадение, если условие выполнено. Если условие не выполняется, используется значение по умолчанию для этого типа. Для ссылочных типов, которые будут иметь значение NULL, будут использоваться числовые типы 0, а использовать логические значения false.

Например, предположим, что мы пытались найти первый фильм, в состав которого входил этот автор:

Movie movie = movies.FirstOrDefault(m => m.Cast.Includes("Matt Eland"));

Поскольку я никогда не снимался в кино, я FirstOrDefaultбы выбрал значение по умолчанию и movieбыло бы установлено на null.

Однако в.NET 6 LINQ теперь позволяет указать настраиваемый параметр, который будет использоваться в случае, если ничто не соответствует условию. Это позволяет избежать необходимости иметь дело со nullзначениями и вместо этого указывает безопасную альтернативу, как показано в следующем коде:

Movie defaultValue = movies.First();

Movie movie = movies.FirstOrDefault(m => m.Cast.Includes("Matt Eland"), defaultValue);

В этом случае, если FirstOrDefaultсовпадение не найдено, он будет использовать defaultValueпараметр.

Читайте также:  Процесс и критерии выбора поставщика программного аутсорсинга

Это изменение также применимо SingleOrDefaultи LastOrDefaultаналогичным образом, где теперь вы можете указать специальный defaultValueпараметр.

Избегание перечисления с помощью TryGetNonEnumeratedCount

При работе с LINQ вы не всегда работаете с каким- Listлибо другим типом коллекции, которая позволяет легко подсчитать длину. Фактически, при работе с определенными типами коллекций, такими как реализующие IQueryable, даже простая операция, такая как вызов Count()метода, может привести к повторной оценке всего запроса.

Для борьбы с этим в.NET 6 добавлен очень специализированный TryGetNonEnumeratedCountметод. Этот метод проверяет, приведет ли определение количества элементов в коллекции к перечислению. В противном случае счетчик создается и сохраняется в outпараметре, а значение trueвозвращается из метода. Если оценивать количество будет вызывать сбор переписываются, метод просто возвращает falseвместо и оставляют outпараметры в 0.

if (movies.TryGetNonEnumeratedCount(out int count))
{
    Console.WriteLine($"The count is {count}");
}
else
{
    Console.WriteLine("Could not get a count of movies without enumerating the collection");
}

Если вы находите этот код или концепцию запутанной, это очень похоже на то, как int.TryParseи другие TryXAPI-интерфейсы в настоящее время работают в библиотеке базовых классов.NET. Единственное отличие состоит в том, что они TryGetNonEnumeratedCountнаправлены на предотвращение потенциально медленных операций из-за перечисления очень большой коллекции или повторного запроса к базе данных.

MaxBy и MinBy

Наконец,.NET 6 предоставляет разработчикам.NET методы расширения MinByи MaxByв LINQ. Эти два метода позволяют вам просматривать вашу коллекцию и находить что-то наибольшее или наименьшее на основе конкретной функции стрелки, которую вы предоставляете.

До.NET 6, чтобы получить сущность, которая имела наибольшее или наименьшее из того, что вам нужно было бы использовать, Maxили Minчтобы найти значение, затем запросите еще раз, чтобы найти связанную сущность:

int numBattles = movies.Max(m => m.NumSpaceBattles);

Movie mostAction = movies.First(m => m.NumSpaceBattles == numBattles);

Это сработало, но требует 2 строки кода вместо 1 и перечисляет коллекцию несколько раз.

С помощью методов расширения.NET 6 MinByи MaxByLINQ теперь мы можем делать это быстрее в одной строке кода:

Movie mostAction = movies.MaxBy(m => m.NumSpaceBattles);

Заключение

Хотя ни одно из этих улучшений не меняет фундаментально то, как разработчики C # работают с LINQ в своем.NET-коде, каждое из них предлагает несколько значительных улучшений качества жизни, что и было целью Microsoft при реализации этих управляемых сообществом функций. Эти изменения также продолжают подтверждать приверженность Microsoft месту.NET в экосистеме программного обеспечения с открытым исходным кодом и разработчикам.NET.

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

Оцените статью
bestprogrammer.ru
Добавить комментарий