Выбрать главу
ное различие: интерфейс 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("