ное
различие: интерфейс IEnumerator наследует от интерфейса IDisposable, тогда
как интерфейс IEnumerator не наследует от него. В интерфейсе IDisposable опреде
ляется метод Dispose(), который служит для освобождения неуправляемых ресурсов.
ПРИМЕЧАНИЕ
В интерфейсе IEnumerable реализуется также необобщенный интерфейс
IEnumerable. Это означает, что в нем поддерживается необобщенный вариант метода
GetEnumerator(). Кроме того, в интерфейсе IEnumerable реализуется необобщен
ный интерфейс IEnumerator, а следовательно, в нем поддерживаются необобщенные ва
рианты свойства Current.
Интерфейс IComparer
Интерфейс IComparer является обобщенным вариантом рассмотренного ранее
интерфейса IComparer. Главное отличие между ними заключается в том, что интер
фейс IComparer обеспечивает типовую безопасность. В нем обобщенный вариант
метода Compare() объявляется следующим образом.
int Compare(Т х, Т у)
В этом методе сравниваются объекты х и у. Он возвращает положительное значе
ние, если значение объекта х больше, чем у объекта у; отрицательное — если значение
объекта х меньше, чем у объекта у; и нулевое значение — если сравниваемые значения
равны.
Интерфейс IEqualityComparer
Интерфейс IEqualityComparer полностью соответствует своему необобщен
ному аналогу EqualityComparer. В нем определяются два следующих метода.
bool Equals (Т х, Т у)
int GetHashCode(Т obj)
Метод Equals() должен возвратить логическое значение true, если значения
объектов х и у равны. А метод GetHashCode() возвращает хеш-код для объекта obj.
Если два сравниваемых объекта равны, то их хеш-коды также должны быть одинаковы.
Интерфейс ISet
Интерфейс ISet был добавлен в версию 4.0 среды .NET Framework. Он опре
деляет поведение обобщенной коллекции, реализующей ряд уникальных элементов.
Этот интерфейс наследует от интерфейсов IEnumerable, IEnumerable, а также
ICollection. В интерфейсе ISet определен ряд методов, перечисленных
в табл. 25.13. Обратите внимание на то, что параметры этих методов указываются как
относящиеся к типу IEnumerable. Это означает, что в качестве второго аргумен
та методу можно передать нечто, отличающееся от объектов типа ISet Но чаще
всего оба аргумента оказываются экземплярами объектов типа ISet
Таблица 25.13. Методы, определенные в интерфейсе ISet
Метод Описание
void ExceptWith(Ienumerable
other)
Удаляет из вызывающего множества те элементы,
которые содержатся в другом множестве other
void
IntersectWith(IEnumerable
other)
После вызова этого метода вызывающее множе
ство содержит пересечение своих элементов с эле
ментами другого множества other
bool
IsProperSubsetOf(IEnumerable
other)
Возвращает логическое значение true, если вы
зывающее множество является правильным под
множеством другого множества other, а иначе —
логическое значение false
bool IsProperSupersetOf(IEnumera
ble other)
возвращает логическое значение true, если вы
зывающее множество является правильным над
множеством другого множества other, а иначе —
логическое значение false
bool IsSubsetOf(IEnumerable
other)
Возвращает логическое значение true, если вы
зывающее множество является подмножеством
другого множества other, а иначе — логическое
значение false
bool
IsSupersetOf(IEnumerable
other)
Возвращает логическое значение true, если вы
зывающее множество является надмножеством
другого множества other, а иначе — логическое
значение false
bool Overlaps(IEnumerable
other)
Возвращает логическое значение true, если вы
зывающее множество и другое множество other
содержат хотя бы один общий элемент, а иначе —
логическое значение false
bool SetEquals(IEnumerable
other)
Возвращает логическое значение true, если все
элементы вызывающего множества и другого мно
жества other оказываются общими, а иначе — ло
гическое значение false. Порядок расположения
элементов не имеет значения, а дублирующиеся
элементы во другом множестве other игнориру
ются
void SymmetricExceptWith
(IEnumerable other)
После вызова этого метода вызывающее множе
ство будет содержать симметрическую разность
своих элементов и элементов другого множества
other
void UnionWith(IEnumerable
other)
После вызова этого метода вызывающее множе
ство будет содержать объединение своих элемен
тов и элементов другого множества other
Структура KeyValuePair
В пространстве имен System.Collections.Generic определена структура
KeyValuePair. Она служит для хранения ключа и его значения
и применяется в классах обобщенных коллекций, в которых хранятся пары "ключ-
значение", как, например, в классе Dictionary. В этой структуре
определяются два следующих свойства.
public TKey Key { get; };
public TValue Value { get; };
В этих свойствах хранятся ключ и значение соответствующего элемента коллекции.
Для построения объекта типа KeyValuePair служит конструктор:
public KeyValuePair(TKey key, TValue value)
где key обозначает ключ, a value — значение.
Классы обобщенных коллекций
Как упоминалось ранее, классы обобщенных коллекций по большей части соот
ветствуют своим необобщенным аналогам, хотя в некоторых случаях они носят другие
имена. Отличаются они также своей организацией и функциональными возможно
стями. Классы обобщенных коллекций определяются в пространстве имен System.
Collections.Generic. В табл. 25.14 приведены классы, рассматриваемые в этой гла
ве. Эти классы составляют основу обобщенных коллекций.
Таблица 25.14. Основные классы обобщенных коллекций
Класс Описание
Dictionary Сохраняет пары “ключ-значение". Обеспечивает такие
же функциональные возможности, как и необобщенный
класс Hashtable
HashSet Сохраняет ряд уникальных значений, используя хеш-
таблицу
LinkedList Сохраняет элементы в двунаправленном списке
List Создает динамический массив. Обеспечивает такие же
функциональные возможности, как и необобщенный
класс ArrayList
Queue Создает очередь. Обеспечивает такие же функциональ
ные возможности, как и необобщенный класс Queue
SortedDictionary
Создает отсортированный список из пар “ключ-
значение”
SortedList Создает отсортированный список из пар "ключ-
значение”. Обеспечивает такие же функциональные воз
можности, как и необобщенный класс SortedList
SortedSet Создает отсортированное множество
Stack Создает стек. Обеспечивает такие же функциональные
возможности, как и необобщенный класс Stack
ПРИМЕЧАНИЕ
В пространстве имен System.Collections.Generic находятся также следующие
классы: класс SynchronizedCollection синхронизированной коллекции на осно
ве класса IList; класс SynchronizedReadOnlyCollection, доступной толь
ко для чтения синхронизированной коллекции на основе класса lList; абстрактный
класс SynchronizedKeyCollection, служащий в качестве базового для клас
са коллекции System.ServiceModel.UriSchemeKeyedCollection; а также класс
KeyedByTypeCollection коллекции, в которой в качестве ключей используются от
дельные типы данных.
Класс List
В классе List реализуется обобщенный динамический массив. Он ничем
принципиально не отличается от класса необобщенной коллекции ArrayList.
В этом классе реализуются интерфейсы ICollection, ICollection, IList,
IList, IEnumerable и IEnumerable. У класса List имеются следующие
конструкторы.
public List()
public List(IEnumerable collection)
public List(int capacity)
Первый конструктор создает пустую коллекцию класса List с выбираемой по
умолчанию первоначальной емкостью. Второй конструктор создает коллекцию типа
List с количеством инициализируемых элементов, которое определяется параметром
collection и равно первоначальной емкости массива. Третий конструктор создает
коллекцию типа List, имеющую первоначальную емкость, задаваемую параметром
capacity. В данном случае емкость обозначает размер базового массива, используе
мого для хранения элементов коллекции. Емкость коллекции, создаваемой в виде ди
намического массива, может увеличиваться автоматически по мере добавления в нее
элементов.
В классе List определяется ряд собственных методов, помимо тех, что уже объ
явлены в интерфейсах, которые в нем реализуются. Некоторые из наиболее часто ис
пользуемых методов этого класса перечислены в табл. 25.15.
Таблица 25.15. Наиболее часто используемые методы, определенные в классе List
Метод Описание
public virtual void
AddRange(Icollection
collection)
Добавляет элементы из коллекции collection в
конец вызывающей коллекции типа ArrayList
public virtual int
BinarySearch(T item)
Выполняет поиск в вызывающей коллекции значе
ния, задаваемого параметром item. Возвращает
индекс совпавшего элемента. Если искомое зна
чение не найдено, возвращается отрицательное
значение. Вызывающий список должен быть отсо
ртирован
Продолжение табл. 25.15
Метод Описание
public int BinarySearch(Т
item, IComparer comparer)
Выполняет поиск в вызывающей коллекции значе
ния, задаваемого параметром item, используя для
сравнения указанный способ, определяемый пара
метром comparer. Возвращает индекс совпавшего
элемента. Если искомое значение не найдено, воз
вращается отрицательное значение. Вызывающий
список должен быть отсортирован
public int BinarySearch(int
index, int count, T item,
IComparer comparer)
Выполняет поиск в вызывающей коллекции значе
ния, задаваемого параметром item, используя для
сравнения указанный способ, определяемый пара
метром comparer. Поиск начинается с элемента,
указываемого по индексу index, и включает ко
личество элементов, определяемых параметром
count. Метод возвращает индекс совпавшего
элемента. Если искомое значение не найдено, воз
вращается отрицательное значение. Вызывающий
список должен быть отсортирован
public List GetRange(int
index, int count)
Возвращает часть вызывающей коллекции. Часть
возвращаемой коллекции начинается с элемента,
указываемого по индексу index, и включает коли
чество элементов, задаваемое параметром count.
Возвращаемый объект ссылается на те же элемен
ты, что и вызывающий объект
public int IndexOf(T item) Возвращает индекс первого вхождения элемента
item в вызывающей коллекции. Если искомый эле
мент не обнаружен, возвращается значение -1
public void InsertRange(int
index, IEnumerable
collection)
Вставляет элементы коллекции collection в вы
зывающую коллекцию, начиная с элемента, указы
ваемого по индексу index
public int LastlndexOf(T
item)
Возвращает индекс последнего вхождения элемен
та item в вызывающей коллекции. Если искомый
элемент не обнаружен, возвращается значение -1
public void RemoveRange(int
index, int count)
Удаляет часть вызывающей коллекции, начиная с
элемента, указываемого по индексу index, и вклю
чая количество элементов, определяемое параме
тром count
public void Reverse() Располагает элементы вызывающей коллекции в
обратном порядке
public void Reverse(int
index, int count)
Располагает в обратном порядке часть вызываю
щей коллекции, начиная с элемента, указываемого
по индексу index, и включая количество элемен
тов, определяемое параметром count
public void Sort() Сортирует вызывающую коллекцию по нарас
тающей
В классе List определяется также собственное свойство Capacity, помимо тех,
что уже объявлены в интерфейсах, которые в нем реализуются. Это свойство объявля
ется следующим образом.
public int Capacity { get; set; }
Свойство Capacity позволяет установить и получить емкость вызывающей коллек
ции в качестве динамического массива. Эта емкость равна количеству элементов, кото
рые может содержать коллекция до ее вынужденного расширения. Такая коллекция
расширяется автоматически, и поэтому задавать ее емкость вручную необязательно.
Но из соображений эффективности это иногда можно сделать, если заранее известно
количество элементов коллекции. Благодаря этому исключаются издержки на выделе
ние дополнительной памяти.
В классе List реализуется также приведенный ниже индексатор, определен
ный в интерфейсе IList.
public Т this[int index] { get; set; }
С помощью этого индексатора устанавливается и получается значение элемента
коллекции, указываемое по индексу index.
В приведенном ниже примере программы демонстрируется применение клас
са List. Это измененный вариант примера, демонстрировавшего ранее класс
ArrayList. Единственное изменение, которое потребовалось для этого, заключалось
в замене класса ArrayList классом List, а также в использовании параметров обоб
щенного типа.
Окончание табл. 25.15
Метод Описание
public void
Sort(IСоmраrеr<Т> comparer)
Сортирует вызывающую коллекцию, используя
для сравнения способ, задаваемый параметром
comparer. Если параметр comparer имеет пустое
значение, то для сравнения используется способ,
выбираемый по умолчанию
public void
Sort(Comparison
comparison)
Сортирует вызывающую коллекцию, используя для
сравнения указанный делегат
public void Sort (int index,
int count, IComparer
comparer)
Сортирует вызывающую коллекцию, используя
для сравнения способ, задаваемый параметром
comparer. Сортировка начинается с элемента, ука
зываемого по индексу index, и включает количе
ство элементов, определяемых параметром count.
Если параметр comparer имеет пустое значение,
то для сравнения используется способ, выбираемый
по умолчанию
public T[] ToArray() Возвращает массив, содержащий копии элементов
вызывающего объекта
public void TrimExcess() Сокращает емкость вызывающей коллекции таким
образом, чтобы она не превышала 10% от количе
ства элементов, хранящихся в ней на данный момент
// Продемонстрировать применение класса List.
using System;
using System.Collections.Generic;
class GenListDemo {
static void Main() {
// Создать коллекцию в виде динамического массива.
List lst = new List();
Console.WriteLine("Исходное количество элементов: " + lst.Count);
Console.WriteLine();
Console.WriteLine("Добавить 6 элементов");
// Добавить элементы в динамический массив.
lst.Add('С');
lst.Add('А');
lst.Add('Е');
lst.Add('В');
lst.Add('D');
lst.Add('F');
Console.WriteLine("Количество элементов: " + lst.Count);
// Отобразить содержимое динамического массива,
// используя индексирование массива.
Console.Write("Текущее содержимое: ");
for (int i=0; i < lst.Count; i++)
Console.Write(lst[i] + " ");
Console.WriteLine("\n");
Console.WriteLine("Удалить 2 элемента ");
// Удалить элементы из динамического массива.
lst.Remove('F');
lst.Remove('А');
Console.WriteLine("Количество элементов: " + lst.Count);
// Отобразить содержимое динамического массива, используя цикл foreach.
Console.Write("Содержимое: ");
foreach(char с in lst)
Console.Write(с + " ");
Console.WriteLine("\n");
Console.WriteLine("Добавить еще 20 элементов");
// Добавить количество элементов, достаточное для
// принудительного расширения массива.
for(int i=0; i < 20; i++)
lst.Add((char)('a' + i));
Console.WriteLine("Текущая емкость: " + lst.Capacity);
Console.WriteLine("Количество элементов после добавления 20 новых: " +
lst.Count);
Console.Write("Содержимое: ");
foreach(char с in lst)
Console.Write(с + " ");
Console.WriteLine("\n");
// Изменить содержимое динамического массива,
// используя индексирование массива.
Console.WriteLine("Изменить три первых элемента");
lst[0] = 'X';
lst [1] = 'Y';
lst[2] = 'Z';
Console.Write("Содержимое: ");
foreach(char с in lst)
Console.Write(с + " ");
Console.WriteLine();
// Следующая строка кода недопустима из-за
// нарушения безопасности обобщенного типа.
// lst.Add(99); // Ошибка, поскольку это не тип char!
}
}
Эта версия программы дает такой же результат, как и предыдущая.
Исходное количество элементов: 0
Добавить 6 элементов
Количество элементов: 6
Текущее содержимое: С А Е В D F
Удалить 2 элемента
Количество элементов: 4
Содержимое: С Е В D
Добавить еще 20 элементов
Текущая емкость: 32
Количество элементов после добавления 20 новых: 24
Содержимое: C E B D a b c d e f g h i j k l m n o p q r s t
Изменить три первых элемента
Содержимое: X Y Z D a b c d e f g h i j k l m n o p q r s t
Класс LinkedList
В классе LinkedList создается коллекция в виде обобщенного двунаправлен
ного списка. В этом классе реализуются интерфейсы ICollection, ICollection,
IEnumerable, IEnumerable, ISerializable и IDeserializationCallback.
В двух последних интерфейсах поддерживается сериализация списка. В классе
LinkedList определяются два приведенных ниже открытых конструктора.
public LinkedList()
public LinkedList(IEnumerable collection)
В первом конструкторе создается пустой связный список, а во втором конструкто
ре — список, инициализируемый элементами из коллекции collection.
Как и в большинстве других реализаций связных списков, в классе LinkedList
инкапсулируются значения, хранящиеся в узлах списка, где находятся также ссылки на
предыдущие и последующие элементы списка. Эти узлы представляют собой объекты
класса LinkedListNode. В классе LinkedListNode предоставляются четыре
следующих свойства.
public LinkedListNode Next { get; }
public LinkedListNode Previous { get; }
public LinkedList List { get; }
public T Value { get; set; }
С помощью свойств Next и Previous получаются ссылки на предыдущий и после
дующий узлы списка соответственно, что дает возможность обходить список в обоих
направлениях. Если же предыдущий или последующий узел отсутствует, то возвра
щается пустая ссылка. Для получения ссылки на сам список служит свойство List.
А с помощью свойства Value можно устанавливать и получать значение, находящееся
в узле списка.
В классе LinkedList определяется немало методов. В табл. 25.16 приве
дены наиболее часто используемые методы данного класса. Кроме того, в клас
се LinkedList определяются собственные свойства, помимо тех, что уже
объявлены в интерфейсах, которые в нем реализуются. Эти свойства приведены
ниже.
public LinkedListNode First { get; }
public LinkedListNode Last { get; }
С помощью свойства First получается первый узел в списке, а с помощью свой
ства Last — последний узел в списке.
Таблица 25.16. Наиболее часто используемые методы, определенные в классе LinkedList
Метод Описание
public LinkedListNode
AddAfter(LinkedListNode
node, T value)
Добавляет в список узел со значением value не
посредственно после указанного узла node. Указы
ваемый узел node не должен быть пустым (null).
Метод возвращает ссылку на узел, содержащий зна
чение value
public void
AddAfter(LinkedListNode
node, LinkedListNode
newNode)
Добавляет в список новый узел newNode непо
средственно после указанного узла node. Ука
зываемый узел node не должен быть пустым
(null). Если узел node отсутствует в списке
или если новый узел newNode является частью
другого списка, то генерируется исключение
InvalidOperationException
public LinkedListNode
AddBefore(LinkedListNode
node, T value)
Добавляет в список узел со значением value непо
средственно перед указанным узлом node. Указы
ваемый узел node не должен быть пустым (null).
Метод возвращает ссылку на узел, содержащий зна
чение value
В приведенном ниже примере программы демонстрируется применение класса
LinkedList.
// Продемонстрировать применение класса LinkedList.
using System;
using System.Collections.Generic;
Окончание табл. 25.16
Метод Описание
public void
AddBefore(LinkedListNode
node, LinkedListNode
newNode)
Добавляет в список новый узел newNode не
посредственно перед указанным узлом node.
Указываемый узел node не должен быть пу
стым (null). Если узел node отсутствует в спи
ске или если новый узел newNode является ча
стью другого списка, то генерируется исключение
InvalidOperationException
public LinkedList
AddFirst(T value)
Добавляет узел со значением value в начало спи
ска. Метод возвращает ссылку на узел, содержащий
значение value
public void
AddFirst(LinkedListNode
node)
Добавляет узел node в начало списка. Если узел
node является частью другого списка, то генериру
ется исключение InvalidOperationException
public LinkedList
AddLast(T value)
Добавляет узел со значением value в конец спи
ска. Метод возвращает ссылку на узел, содержащий
значение value
public void
AddLast(LinkedListNode node)
Добавляет узел node в конец списка. Если узел
node является частью другого списка, то генериру
ется исключение InvalidOperationException
public LinkedList Find(T
value)
Возвращает ссылку на первый узел в списке, име
ющий значение value. Если искомое значение
value отсутствует в списке, то возвращается пустое
значение
public LinkedList
FindLast(T value)
Возвращает ссылку на последний узел в списке,
имеющий значение value. Если искомое значение
value отсутствует в списке, то возвращается пустое
значение
public bool Remove(T value) Удаляет из списка первый узел, содержащий значе
ние value. Возвращает логическое значение true,
если узел удален, т.е. если узел со значением value
обнаружен в списке и удален; в противном случае
возвращает логическое значение false
public void
Remove(LinkedList node)
Удаляет из списка узел, соответствующий ука
занному узлу node. Если узел node отсут
ствует в списке, то генерируется исключение
InvalidOperationException
public void RemoveFirst() Удаляет из списка первый узел
public void RemoveLast() Удаляет из списка последний узел
class GenLinkedListDemo {
static void Main() {
// Создать связный список.
LinkedList ll = new LinkedList();
Console.WriteLine("Исходное количество элементов в списке: " + ll.Count)
Console.WriteLine();
Console.WriteLine("Добавить в список 5 элементов");
// Добавить элементы в связный список.
ll.AddFirst('А');
ll.AddFirst('В');
ll.AddFirst('С');
ll.AddFirst('D');
ll.AddFirst('Е');
Console.WriteLine("Количество элементов в списке: " + ll.Count);
// Отобразить связный список, обойдя его вручную.
LinkedListNode node;
Console.Write("Отобразить содержимое списка по ссылкам: ");
for(node = ll.First; node != null; node = node.Next)
Console.Write(node.Value + " ");
Console.WriteLine("\n");
// Отобразить связный список, обойдя его в цикле foreach.
Console.Write("Отобразить содержимое списка в цикле foreach: ");
foreach(char ch in 11)
Console.Write(ch + " ");
Console.WriteLine("\n");
// Отобразить связный список, обойдя его вручную в обратном направлении.
Console.Write("