Коллекции
Хотя в языке C# есть массивы, которые хранят в себе наборы однотипных объектов, но работать с ними не всегда удобно. Например, массив хранит фиксированное количество объектов, однако что если мы заранее не знаем, сколько нам потребуется объектов. И в этом случае намного удобнее применять коллекции. Еще один плюс коллекций состоит в том, что некоторые из них реализует стандартные структуры данных, например, стек, очередь, словарь, которые могут пригодиться для решения различных специальных задач. Большая часть классов коллекций содержится в пространстве имен System.Collections.Generic .
Класс List<T> из пространства имен System.Collections.Generic представляет простейший список однотипных объектов. Класс List типизируется типом, объекты которого будут хранится в списке.
Мы можем создать пустой список:
В данном случае объект List типизируется типом string . А это значит, что хранить в этом списке мы можем только строки.
Можно сразу при создании списка инициализировать его начальными значениями. В этом случае элементы списка помещаются после вызова конструктора в фигурных скобках
В данном случае в список помещаются три строки
Также можно при создании списка инициализировать его элементами из другой коллекции, например, другого списка:
Можно совместить оба способа:
В данном случае в списке employees будет четыре элемента ( < "Tom", "Bob", "Sam", "Mike" >) — три добавляются из списка people и один элемент задается при инициализации.
Подобным образом можно работать со списками других типов, например:
Установка начальной емкости списка
Еще один конструктор класса List принимает в качестве параметра начальную емкость списка:
Указание начальной емкости списка позволяет в будущем увеличить производительность и уменьшить издержки на выделение памяти при добавлении элементов. Поскольку динамическое добавление в список может приводить на низком уровне к дополнительному выделению памяти, что снижает производительность. Если же мы знаем, что список не будет превышать некоторый размер, то мы можем передать этот размер в качестве емкости списка и избежать дополнительных выделений памяти.
Также начальную емкость можно установить с помощью свойства Capacity , которое имеется у класса List.
Обращение к элементам списка
Как и массивы, списки поддерживают индексы, с помощью которых можно обратиться к определенным элементам:
Длина списка
С помощью свойства Count можно получить длину списка:
Перебор списка
C# позволяет осуществить перебор списка с помощью стандартного цикла foreach :/p>
Также можно использовать другие типы циклов и в комбинации с индексами перебирать списки:
Методы списка
Среди его методов можно выделить следующие:
void Add(T item) : добавление нового элемента в список
void AddRange(IEnumerable<T> collection) : добавление в список коллекции или массива
int BinarySearch(T item) : бинарный поиск элемента в списке. Если элемент найден, то метод возвращает индекс этого элемента в коллекции. При этом список должен быть отсортирован.
void CopyTo(T[] array) : копирует список в массив array
void CopyTo(int index, T[] array, int arrayIndex, int count) : копирует из списка начиная с индекса index элементы, количество которых равно count, и вставляет их в массив array начиная с индекса arrayIndex
bool Contains(T item) : возвращает true , если элемент item есть в списке
void Clear() : удаляет из списка все элементы
bool Exists(Predicate<T> match) : возвращает true , если в списке есть элемент, который соответствует делегату match
T? Find(Predicate<T> match) : возвращает первый элемент, который соответствует делегату match. Если элемент не найден, возвращается null
T? FindLast(Predicate<T> match) : возвращает последний элемент, который соответствует делегату match. Если элемент не найден, возвращается null
List<T> FindAll(Predicate<T> match) : возвращает список элементов, которые соответствуют делегату match
int IndexOf(T item) : возвращает индекс первого вхождения элемента в списке
int LastIndexOf(T item) : возвращает индекс последнего вхождения элемента в списке
List<T> GetRange(int index, int count) : возвращает список элементов, количество которых равно count, начиная с индекса index.
void Insert(int index, T item) : вставляет элемент item в список по индексу index. Если такого индекса в списке нет, то генерируется исключение
void InsertRange(int index, collection) : вставляет коллекцию элементов collection в текущий список начиная с индекса index. Если такого индекса в списке нет, то генерируется исключение
bool Remove(T item) : удаляет элемент item из списка, и если удаление прошло успешно, то возвращает true. Если в списке несколько одинаковых элементов, то удаляется только первый из них
void RemoveAt(int index) : удаление элемента по указанному индексу index. Если такого индекса в списке нет, то генерируется исключение
void RemoveRange(int index, int count) : параметр index задает индекс, с которого надо удалить элементы, а параметр count задает количество удаляемых элементов.
int RemoveAll((Predicate<T> match)) : удаляет все элементы, которые соответствуют делегату match. Возвращает количество удаленных элементов
void Reverse() : изменяет порядок элементов
void Reverse(int index, int count) : изменяет порядок на обратный для элементов, количество которых равно count, начиная с индекса index
void Sort() : сортировка списка
void Sort(IComparer<T>? comparer) : сортировка списка с помощью объекта comparer, который передается в качестве параметра
List<T>.Count Свойство
Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
Получает число элементов, содержащихся в интерфейсе List<T>.
Значение свойства
Число элементов, содержащихся в интерфейсе List<T>.
Реализации
Примеры
В следующем примере показано, как проверить емкость и количество объектов List<T> , содержащих простой бизнес-объект, иллюстрирует использование TrimExcess метода для удаления дополнительной емкости.
В следующем примере показано значение Count свойства в различных точках в жизненном цикле списка. После создания и заполнения списка и отображения Capacity его элементов отображаются и Count свойства. Эти свойства снова отображаются после TrimExcess вызова метода и снова после очистки содержимого списка.
Комментарии
Capacity — это количество элементов, которые List<T> могут храниться перед изменением размера. Count — это количество элементов, которые фактически находятся в элементе List<T>.
Capacity всегда больше или равно Count. При Count превышении при добавлении Capacity элементов емкость увеличивается путем автоматического перераспределения внутреннего массива перед копированием старых элементов и добавлением новых элементов.
Получение значения данного свойства является операцией порядка сложности O(1).
Операции Count, LongCount и Sum

Операция Count возвращает количество элементов во входной последовательности. Эта операция имеет два прототипа, описанные ниже:
Первый прототип Count
Этот прототип операции Count возвращает общее количество элементов во входной последовательности, проверяя сначала, реализует ли она интерфейс ICollection<T>, и если да, то получает счетчик последовательности через реализацию этого интерфейса. Если же входная последовательность source не реализует интерфейс ICollection<T>, операция Count перечисляет всю эту последовательность, подсчитывая количество элементов.
Второй прототип Count
Второй прототип операции Count перечисляет входную последовательность source и подсчитывает все элементы, которые заставляют делегат метода predicate вернуть true:
Если любой из аргументов равен null, генерируется исключение ArgumentNullException. Если значение count превышает Int32.MaxValue, генерируется исключение OverflowException.
Код ниже начинается с использования первого прототипа. Сколько элементов содержится в последовательности cars? Затем используется второй прототип, подсчитывая количество машин, начинающихся с «A»:
Результат работы этого кода:

LongCount
Операция LongCount возвращает количество элементов входной последовательности как значение типа long. Эта операция имеет два прототипа, полностью идентичных прототипам операции Count, за тем лишь исключением, что они возвращают число элементов, имеющих тип long, а не int.
Давайте рассмотрим пример использования операции LongCount. Можно было бы просто повторить тот же пример, который сопровождал описание операции Count, изменив соответствующие места на тип long, но это не слишком наглядно. Поскольку нереально описать достаточно длинную статическую последовательность, для которой понадобилась бы операция LongCount, она генерируется с помощью стандартной операции запроса:
Как видите, были сгенерированы две последовательности с использованием операции Range и соединены вместе с помощью операции Concat.
Перед запуском примера наберитесь терпения — он выполняется долго, возможно, даже несколько минут. Например, на машине с четырехядерным процессором и 4 Гбайт памяти для этого потребовалось около минуты. В конце концов, будут сгенерированы две последовательности, каждая по 2 147 483 647 элементов. Ниже показан результат:

Операция Sum возвращает сумму числовых значений, содержащихся в элементах последовательности. Эта операция имеет два прототипа, описанные ниже:
Первый прототип Sum
Тип Numeric должен быть одним из int, long, double или decimal, либо одним из их допускающих null эквивалентов: int?, long?, double? или decimal?.
Первый прототип операции Sum возвращает сумму всех элементов входной последовательности source. Пустая последовательность приведет к возврату нуля. Операция Sum не включает значения null в результат для числовых типов, допускающих null.
Второй прототип Sum
Второй прототип Sum ведет себя так же, как и первый, но суммирует только те значения входной последовательности, которые выбраны делегатом метода selector.
Если любой из аргументов равен null, генерируется исключение ArgumentNullException. Если сумма оказывается слишком большой, чтобы уместиться в тип Numeric, и если тип Numeric отличается от decimal или decimal?, генерируется исключение OverflowException. Если же типом Numeric является decimal или decimal?, возвращается положительная или отрицательная бесконечность.
Ниже показан пример использования первого прототипа операции Sum:

Теперь попробуем второй прототип, как показано ниже. В этом примере задействован общий класс EmployeeOptionEntry, и будут суммироваться опционы для всех сотрудников:
Вместо того чтобы пытаться суммировать весь элемент, что не имело бы смысла в данном примере, поскольку речь идет об объекте сотрудника, можно использовать элемент selector второго прототипа, чтобы извлечь только интересующие члены — в данном случае optionsCount. Результат выполнения этого кода показан ниже: