- •А.А. Волосевич
- •Содержание
- •1. Работа с числами
- •2. Представление даты и времени
- •3. Работа со строками и текстом
- •4. Преобразование информации
- •5. Сравнение для выяснения равенства
- •6. Сравнение для выяснения порядка
- •7. Жизненный цикл объектов
- •7.1. Алгоритм сборки мусора
- •7.2. Финализаторы и интерфейс iDisposable
- •7.3. Слабые ссылки
- •8. Перечислители и итераторы
- •9. Стандартные интерфейсы коллекций
- •10. Массивы и класс System.Array
- •11. Типы для работы с коллекциями-списками
- •12. Типы для работы с коллекциями-множествами
- •13. Типы для работы с коллекциями-словарями
- •14. Типы для создания пользовательских коллекций
- •15. Технология linq to Objects
- •1. Оператор условия Where().
- •2. Операторы проекций.
- •3. Операторы упорядочивания.
- •4. Оператор группировки GroupBy().
- •5. Операторы соединения.
- •6. Операторы работы с множествами.
- •7. Операторы агрегирования.
- •8. Операторы генерирования.
- •9. Операторы кванторов и сравнения.
- •10. Операторы разбиения.
- •11. Операторы элемента.
- •12. Операторы преобразования.
- •16. Работа с объектами файловой системы
- •17. Ввод и вывод информации
- •17.1. Потоки данных и декораторы потоков
- •2. Классы для работы с потоками, связанными с хранилищами.
- •3. Декораторы потоков.
- •4. Адаптеры потоков.
- •17.2. Адаптеры потоков
- •18. Основы xml
- •19. Технология linq to xml
- •20. Дополнительные возможности обработки xml
- •21. Сериализация времени выполнения
- •22. Контракты данных и xml-сериализация
- •23. Состав и взаимодействие сборок
- •24. Метаданные и получение информации о типах
- •25. Позднее связывание и кодогенерация
- •26. Атрибуты
- •27. Динамическое связывание
- •28. Файлы конфигурации
- •29. Диагностика и мониторинг
- •30. Процессы и домены
- •31. Основы многопоточного программирования
- •32. Синхронизация потоков
- •32.1. Критические секции
- •32.2. Синхронизация на основе подачи сигналов
- •32.3. Неблокирующие средства синхронизации
- •32.4. Разделение данных между потоками
- •33. Библиотека параллельных задач
- •33.1. Параллелизм на уровне задач
- •33.2. Параллелизм при императивной обработке данных
- •33.3. Параллелизм при декларативной обработке данных
- •33.4. Обработка исключений и отмена выполнения задач
- •33.5. Коллекции, поддерживающие параллелизм
- •34. Асинхронный вызов методов
- •Литература
11. Типы для работы с коллекциями-списками
Рассмотрим типы из базовой библиотеки платформы .NET, применяемые при работе с коллекциями со списковой семантикой.
Класс List<T> из пространства имён System.Collections.Generic – основной класс для представления наборов, которые допускают динамическое добавление элементов1. Для хранения данных набора используется внутренний массив. Класс List<T> реализует интерфейсы IList<T> и IList. В табл. 8 представлено описание public-элементов класса List<T>.
Таблица 8
Элементы класса List<T>
Элемент |
Описание |
Добавление и удаление элементов |
|
Add() |
Добавление одного элемента |
AddRange() |
Добавление набора элементов |
Insert() |
Вставка элемента в заданную позицию |
InsertRange() |
Вставка набора элементов |
Remove() |
Удаление элемента |
RemoveAt() |
Удаление элемента на указанной позиции со сдвигом остальных |
RemoveRange() |
Удаление диапазона элементов |
RemoveAll() |
Удаление всех элементов, удовлетворяющих заданному предикату |
Индексирование элементов |
|
this[int index] |
Основной индексатор |
GetRange() |
Получение подсписка |
GetEnumerator() |
Получение перечислителя |
Поиск и сортировка |
|
BinarySearch() |
Поиск элемента в упорядоченном наборе |
IndexOf() |
Индекс первого вхождения своего аргумента в набор |
LastIndexOf() |
Индекс последнего вхождения своего аргумента в набор |
Contains() |
Проверка, содержится ли указанный элемент в наборе |
Exists() |
Проверка, содержит ли набор элемент, удовлетворяющий предикату |
Find() |
Возвращает первый элемент, удовлетворяющий предикату, который задан как аргумент метода |
FindLast() |
Возвращает первый элемент с конца набора, удовлетворяющий предикату, который задан как аргумент метода |
FindAll() |
Возвращает все элементы набора, удовлетворяющие предикату |
FindIndex() |
Возвращает индекс первого вхождения элемента, удовлетворяющего предикату, который задан как аргумент метода |
FindLastIndex() |
Возвращает индекс последнего вхождения элемента, удовлетворяющего предикату, который задан как аргумент метода |
TrueForAll() |
Возвращает true, если заданный предикат верен для всех элементов |
Sort() |
Сортировка набора (возможно, с применением собственного объекта для сравнения элементов) |
Экспорт и конвертирование элементов |
|
ToArray() |
Преобразование набора в массив |
CopyTo() |
Копирование набора или его части в массив |
AsReadOnly() |
Преобразование набора в коллекцию только для чтения |
ConvertAll() |
Конвертирование набора одно типа в набор другого типа |
Другие методы и свойства |
|
Count |
Количество элементов в наборе |
Capacity |
Ёмкость набора |
TrimExcess() |
Усечение размера внутреннего массива до необходимой минимальной величины |
Clear() |
Очистка списка (удаление всех элементов) |
Reverse() |
Изменение порядка элементов на противоположный |
ForEach() |
Выполняет указанное действие для всех элементов списка |
Класс List<T> имеет три конструктора. Первый из них – обычный конструктор без параметров. Второй конструктор позволяет создать набор на основе коллекции – производится копирование элементов коллекции в список. Третий конструктор принимает в качестве аргумента начальную ёмкость набора. Ёмкость набора (capacity) – это количество элементов набора, которое он способен содержать без увеличения размера внутреннего массива.
Следующий код демонстрирует использование некоторых свойств и методов класса List<T>. Обратите внимание, что для добавления элементов в созданный набор применяется возможность инициализации классов-коллекций.
List<string> words = new List<string> {"melon", "avocado"};
words.AddRange(new[] {"banana", "plum"});
words.Insert(0, "lemon");
words.InsertRange(0, new[] {"peach", "apple"});
words.Remove("melon");
words.RemoveAt(3);
words.RemoveAll(s => s.StartsWith("a"));
List<string> subset = words.GetRange(1, 2);
string[] wordsArray = words.ToArray();
List<int> lengths = words.ConvertAll<int>(s => s.Length);
На примере List<T> рассмотрим особенность, присущую использованию коллекций в языке C#. Если коллекция хранит структуры, то C# не позволяет изменить части структуры при помощи индексатора коллекции (так как индексатор является функцией, возвращающей копию элемента коллекции):
public struct Student
{
public string Name { get; set; }
}
var list = new List<Student> {new Student {Name = "Ivanov"}};
list[0].Name = "Petrov"; // ошибка компиляции!
Класс LinkedList<T> служит для представления двусвязного списка. Такой список позволяет осуществлять вставку и удаление элемента без сдвига остальных элементов. Однако доступ к элементу по индексу требует прохода по списку. LinkedList<T> реализует интерфейсы ICollection и ICollection<T>. Каждый элемент двусвязного списка представлен объектом LinkedListNode<T>.
public sealed class LinkedListNode<T>
{
public LinkedList<T> List { get; }
public LinkedListNode<T> Next { get; }
public LinkedListNode<T> Previous { get; }
public T Value { get; set; }
}
При добавлении элемента можно указать, чтобы он помещался в начало списка, или в конец списка, или относительно существующего в списке элемента. Для этого класс LinkedList<T> содержит специальные методы:
public void AddFirst(LinkedListNode<T> node);
public LinkedListNode<T> AddFirst(T value);
public void AddLast(LinkedListNode<T> node);
public LinkedListNode<T> AddLast(T value);
public void AddAfter(LinkedListNode<T> node,
LinkedListNode<T> newNode);
public LinkedListNode<T> AddAfter(LinkedListNode<T> node, T value);
public void AddBefore(LinkedListNode<T> node,
LinkedListNode<T> newNode);
public LinkedListNode<T> AddBefore(LinkedListNode<T> node, T value);
Аналогичные методы существуют и для удаления элементов списка:
public void RemoveFirst();
public void RemoveLast();
public bool Remove(T value);
public void Remove(LinkedListNode<T> node);
Класс LinkedList<T> содержит свойства для числа элементов, для указания на первый и последний элемент. Имеются методы для поиска элементов.
Ниже приведён пример использования LinkedList<T>.
var tune = new LinkedList<string>();
tune.AddFirst("do"); // do
tune.AddLast("so"); // do - so
tune.AddAfter(tune.First, "re"); // do - re- so
tune.AddAfter(tune.First.Next, "mi"); // do - re - mi- so
tune.AddBefore(tune.Last, "fa"); // do - re - mi - fa- so
tune.RemoveFirst(); // re - mi - fa - so
tune.RemoveLast(); // re - mi - fa
var miNode = tune.Find("mi");
tune.Remove(miNode); // re - fa
tune.AddFirst(miNode); // mi - re - fa
Классы Queue<T> и Stack<T> реализуют структуры данных «очередь» и «стек» на основе массива1. Конструкторы этих классов, как и конструкторы класса List<T>, позволяют создать объект на основе другой коллекции, а также указать значение для ёмкости (но ёмкость не доступна в виде отдельного свойства). Элементы классов вполне предсказуемы и описаны в табл. 9 и табл. 10.
Таблица 9
Элементы класса Queue<T>
Элемент |
Описание |
Clear() |
Очистка очереди (удаление всех элементов) |
Contains() |
Проверка, содержится ли указанный элемент в очереди |
CopyTo() |
Копирование очереди в массив |
Count |
Количество элементов (свойство только для чтения) |
Dequeue() |
Извлечение элемента из очереди |
Enqueue() |
Помещение элемента в очередь |
GetEnumerator() |
Получение перечислителя |
Peek() |
Чтение очередного элемента без его удаления из очереди |
ToArray() |
Преобразование очереди в массив |
TrimExcess() |
Усечение размера внутреннего массива до необходимой минимальной величины |
Таблица 10
Элементы класса Stack<T>
Элемент |
Описание |
Clear() |
Очистка стека (удаление всех элементов) |
Contains() |
Проверка, содержится ли указанный элемент в стеке |
CopyTo() |
Копирование стека в массив |
Count |
Количество элементов (свойство только для чтения) |
GetEnumerator() |
Получение перечислителя |
Peek() |
Чтение очередного элемента без его удаления из стека |
Pop() |
Извлечение элемента из стека |
Push() |
Помещение элемента в стек |
ToArray() |
Преобразование стека в массив |
TrimExcess() |
Усечение размера внутреннего массива до необходимой минимальной величины |