Выражения коллекций C# и инициализаторы коллекций

Выражения коллекций C# и инициализаторы коллекций

3 апреля 2024 г.

Недавно меня вдохновили некоторые интересные характеристики производительности инициализаторов коллекций и выражений коллекций в C#, и я захотел написать вводную статью. Эта статья будет частью небольшой серии, в которой я впервые познакомлю вас с синтаксисом, с которым нам приходится работать как для выражений коллекций, так и для инициализаторов коллекций в C#. Мы увидим разницу в стиле и читабельности — над чем команда dotnet работает, чтобы сделать язык менее громоздким, сохраняя при этом выразительность.

Как только вы почувствуете, как работают инициализаторы коллекций и выражения коллекций в C#, вы сможете проверить некоторые тесты производительности на них.

Нет смысла гипероптимизировать эти вещи, если вы не понимаете основ!


Использование List с инициализаторами коллекций в C

Инициализаторы коллекций в C# обеспечивают лаконичный и читаемый способ заполнения коллекций, таких как List<T>, при создании экземпляра. Эта функция упрощает код, позволяя инициализировать коллекцию набором предопределенных элементов без необходимости многократного вызова метода Add.

В следующих подразделах будут показаны примеры инициализаторов коллекций типа List<T>. Имейте в виду, что весь смысл этих инициализаторов заключается в том, чтобы с самого начала определить коллекции с элементами в них, что избавит нас от необходимости делать что-то вроде следующего:

List<string> devLeaderCoolList = new List<string>();
devLeaderCoolList.Add("Hello");
devLeaderCoolList.Add(", ");
devLeaderCoolList.Add("World!");

Итак, взяв это за отправную точку, учтите, что следующие примеры сделают это более простым и кратким.

Пример 1. Инициализация списка целых чисел

List<int> primeNumbers = new List<int> { 2, 3, 5, 7, 11, 13, 17 };

В этом примере демонстрируется инициализация List<int> коллекцией простых чисел. Числа заключаются в фигурные скобки {} и разделяются запятыми сразу после создания списка.

Мы также можем использовать немного более сокращенный синтаксис, чтобы удалить все дублированное определение типа с правой стороны знака равенства:

List<int> primeNumbers = new() { 2, 3, 5, 7, 11, 13, 17 };

Пример 2: объединение инициализаторов объектов и коллекций

public class Student
{
    public string Name { get; set; }
    public int Age { get; set; }
}

List<Student> students = new List<Student>
{
    new Student { Name = "Alice", Age = 22 },
    new Student { Name = "Bob", Age = 24 }
};

Здесь мы объединяем инициализаторы объектов и коллекций для создания List<Student>, где каждый объект Student инициализируется с помощью Name и Age< /код> свойства. Такой подход упрощает процесс заполнения коллекции полностью инициализированными объектами. Здесь важно обратить внимание на то, что синтаксис инициализатора объекта очень похож на синтаксис инициализатора коллекции, но на самом деле мы делаем две вещи:

  1. Присвоение значений свойствам новых объектов
  2. Назначение элементов коллекции при ее создании
  3. Пример 3. Использование сложных выражений

    List<double> areas = new List<double>
    {
        Math.PI * Math.Pow(3, 2),
        Math.PI * Math.Pow(5, 2)
    };
    

    В этом примере инициализируется List<double> областями кругов (с использованием πr²), где r — это радиус. Он показывает, что выражения, включая вызовы методов, можно использовать в инициализаторах коллекций, то есть нет ограничений на константы или предварительно вычисленные значения.

    Пример 4: Инициализаторы вложенных коллекций

    public class Classroom
    {
        public List<Student> Students { get; set; }
    }
    
    List<Classroom> classrooms = new List<Classroom>
    {
        new Classroom
        {
            Students = new List<Student>
            {
                new Student { Name = "Alice", Age = 22 }
            }
        },
        new Classroom
        {
            Students = new List<Student>
            {
                new Student { Name = "Bob", Age = 24 }
            }
        }
    };
    

    В этом примере показано, как использовать инициализаторы вложенных коллекций для инициализации списка объектов Classroom, каждый из которых содержит список объектов Student. Он очень похож на пример 2, который мы уже рассматривали, но здесь мы поднимаем ситуацию еще на один уровень, показывая несколько инициализаторов коллекций и инициализацию объектов.

    Пример 5: Простая инициализация списка с помощью выражений коллекции

    В C# 11 мы начинаем получать новый, более интересный синтаксис для выражения коллекции. Это был шаг вперед в уменьшении многословности объявлений коллекций с использованием большего количества сокращений, как и в других языках. Microsoft говорит в своей документации:

    <блок-цитата>

    Вы можете использовать выражение коллекции для создания общих значений коллекции. Выражение коллекции – это краткий синтаксис, который при вычислении может быть присвоен множеству различных типов коллекций. Выражение коллекции содержит последовательность элементов между скобками [ и ].

    Microsoft

    Давайте рассмотрим пример:

    List<int> evenNumbers = [2, 4, 6, 8, 10];
    

    В этом примере демонстрируется простая инициализация List<int> с использованием нового синтаксиса выражений коллекции, что делает код более кратким и читабельным.

    Пример 6: объединение коллекций с помощью оператора расширения

    И в C# 12 есть еще больше преимуществ — мы получить оператор распространения для инициализации коллекции:

    List<int> firstBatch = [1, 2, 3];
    List<int> combinedList = [0, ..firstBatch, 4];
    

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


    Куда мы идем с этим?

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

    Но что дальше? ТАК заботимся ли мы о читабельности?

    Я имею в виду, да. Честно говоря, я считаю, что невероятно важно уделять первоочередное внимание читабельности кода. Но если вам так же любопытно, как и мне, вы можете увидеть в Интернете подобную публикацию от Дэйва Каллана и очень заинтересоваться. любопытно:

    Dave Callan - Collection Initializer Collection Expression Benchmarks

    И поскольку именно это вызвало у меня интерес и заставило написать эту статью в качестве вводного курса, возможно, вас заинтересуют эксплуатационные характеристики, которые я исследовал!


    Подведение итогов по инициализаторам и выражениям коллекций C#

    Теперь, когда вы ознакомились с различными примерами синтаксиса, к которым у нас есть доступ, вы можете принять собственное обоснованное решение о том, какой из них наиболее удобен для вас. Я думаю, что всегда важно потратить некоторое время на поиск альтернатив, чтобы вы могли понять разные точки зрения, даже если кажется, что различия могут быть незначительными. Вероятно, вам придется читать и писать инициализаторы коллекций и выражения коллекций МНОГО раз за свою карьеру разработчика программного обеспечения, так почему бы не оптимизировать свой выбор?

    Говоря об оптимизации… подождите, пока не увидите следующая статья о производительности инициализаторов коллекций!

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


    Также опубликовано здесь. .


    Оригинал