- •939 Сторінка в djvu 54 сторінка
- •Int Count { get; } bool IsReadOnly { get; }
- •Int Compare(т х, т у)
- •Int CompareTo(object obj)
- •Int CompareTo(т other)
- •Int Compare(object X, object y)
- •Int Compare(т х, т у)
- •Inv.Add(new Inventory("Викрутки", 8.29, 2)); inv.Add(new Inventory("Молотки", 3.50, 4)); inv.Add(new Inventory("Дриля", 19.88, 8));
- •Void Reset()
Int Compare(т х, т у)
У цьому методі рівняються об'єкти х и y. Він повертає позитивне значення, якщо значення об'єкта х більше, ніж в об'єкта y; негативне - якщо значення об'єкта х менше, ніж в об'єкта y; і нульове значення - якщо порівнювані значення рівні.
Інтерфейс IEqualityComparer<T>
Інтерфейс IEqualityComparer<T> повністю відповідає своєму неузагальненому аналогу EqualityComparer. У ньому визначаються два наступні методи.
bool Equals(Т х, Т у) int GetHashCode(Т obj)
Метод Equals ( ) повинен повернути логічне значення true, якщо значення об'єктів х и y рівні. А метод GetHashCode ( ) повертає хеш-код для об'єкта obj. Якщо два порівнюваних об'єкти рівні, то їхній хеш-код також повинні бути однакові.
Інтерфейс ISet<T>
Інтерфейс ISet<T> був доданий у версію 4.0 середовища .NET Framework. Він визначає поводження узагальненої колекції, що реалізує ряд унікальних елементів. Цей інтерфейс успадковує від інтерфейсів IEnumerable, IEnumerable<T>, а також ICollection<T>. В інтерфейсі ISet<T> визначений ряд методів, перерахованих у табл. 25.13. Зверніть увагу на те, що параметри цих методів указуються як стосовні до типу IEnumerable<Т>. Це означає, що як другий аргумент методу можна передати щось, що відрізняється від об'єктів типу ISeT<Т>. Але найчастіше обидва аргументи виявляються екземплярами об'єктів типу ISeT<Т>.
Таблиця 25.13. Методи, певні в інтерфейсі ISeT<Т>
Метод |
Опис |
void ExceptWith(Ienumerable<T> other) |
Видаляє із зухвалої безлічі ті елементи, які втримуються в іншій безлічі other |
Void IntersectWith(IEnumerable<T> other) |
Після виклику цього методу зухвала безліч містить перетинання своїх елементів з елементами іншої безлічі other |
Bool IsProperSubsetOf(IEnumerable<T> other) |
Повертає логічне значення true, якщо зухвала безліч є правильною підмножиною іншої безлічі other, а інакше - логічне значення false |
bool IsProperSupersetOf(IEnumera ble<T> other) |
Повертає логічне значення true, якщо зухвала безліч є правильною надбезліччю іншої безлічі other, а інакше - логічне значення false |
bool IsSubsetOf(IEnumerable<T> other) |
Повертає логічне значення true, якщо зухвала безліч є підмножиною іншої безлічі other, а інакше - логічне значення false |
Bool IsSupersetOf(IEnumerable<T> other) |
Повертає логічне значення true, якщо зухвала безліч є надбезліччю іншої безлічі other, а інакше - логічне значення false |
bool Overlaps(IEnumerable<T> other) |
Повертає логічне значення true, якщо зухвала безліч й інша безліч other містять хоча б один загальний елемент, а інакше - логічне значення false |
bool SetEquals(IEnumerable<T> other) |
Повертає логічне значення true, якщо всі елементи зухвалої безлічі й іншої безлічі other виявляються загальними, а інакше -логічне значення false. Порядок розташування елементів не має значення, а елементи, що дублюються, в іншій безлічі other ігноруються |
void SymmetricExceptWith (IEnumerable<T> other) |
Після виклику цього методу зухвала безліч буде містити симетричну різницю своїх елементів й елементів іншої безлічі other |
void UnionWith(IEnumerable<T> other) |
Після виклику цього методу зухвала безліч буде містити об'єднання своїх элемен- тов й елементів іншої безлічі other |
Структура KeyValuePair<TKey, TValue>
У просторі імен System.Collections.Generic визначена структура KeyValuePairCTKey, TValue Вона служить для зберігання ключа і його значення й застосовується в класах узагальнених колекцій, у яких зберігаються пари "ключ- значення", як, наприклад, у класі DictionaryCTKey, TValue. У цій структурі визначаються дві наступні властивості.
public Ткеу Key ( get; }; public TValue Value { get; );
У цих властивостях зберігаються ключ і значення відповідного елемента колекції. Для побудови об'єкта типу KeyValuePair<TKey, TValue> служить конструктор:
public KeyValuePair(Ткеу key, TValue value)
де кеу позначає ключ, a value - значення.
Класи узагальнених колекцій
Як згадувалося раніше, класи узагальнених колекцій по більшій частині відповідають своїм неузагальненим аналогам, хоча в деяких випадках вони носять інші імена. Відрізняються вони також своєю організацією й функціональними можливостями. Класи узагальнених колекцій визначаються в просторі імен System. Collections.Generic. У табл. 25.14 наведені класи, розглянуті в цій главі. Ці класи становлять основу узагальнених колекцій.
Таблиця 25.14. Основні класи узагальнених колекцій
Клас |
Опис |
Dictionary<Tkey, TValue> |
Зберігає пари “джерело-значення”. Забезпечує такі ж функціональні можливості, як і неузагальнений клас Hashtable |
HashSet<T> |
Зберігає ряд унікальних значень, використовуючи хеш- таблицю |
LinkedList<T> |
Зберігає елементи у двунаправленном списку |
List<T> |
Створює динамічний масив. Забезпечує такі ж функціональні можливості, як і неузагальнений клас ArrayList |
Queue<T> |
Створює черга. Забезпечує такі ж функціональні можливості, як і неузагальнений клас Queue |
SortedDictionary<TKey, TValue> |
Створює відсортований список з пар “ключ- значення" |
SortedList<TKey, TValue> |
Створює відсортований список з пар “ключ- значення”. Забезпечує такі ж функціональні можливості, як і неузагальнений клас SortedList |
SortedSet<T> |
Створює відсортована безліч |
Stack<T> |
Створює стек. Забезпечує такі ж функціональні можливості, як і неузагальнений клас Stack |
ПРИМІТКА
У просторі імен System. Collections. Generic перебувають також наступні класи: клас SynchronizedCollection<T> синхронізованої колекції на основі класу IList<T>; клас SynchronizedReadOnlyCollection<T>, доступної тільки для читання синхронізованої колекції на основі класу IList<T>; абстрактний клас SynchronizedKeyCollection<K, Т>, службовець у якості базового для класу колекції System. ServiceModel. UriSchemeKeyedCollection; а також клас KeyedByTypeCollection<T> колекції, у якій як ключі використаються окремі типи даних.
Клас List<T>
У класі List<T> реалізується узагальнений динамічний масив. Він нічим принципово не відрізняється від класу неузагальненої колекції ArrayList. У цьому класі реалізуються інтерфейси ICollection, ICollection<T>, IList, IList<T>, IEnumerable і IEnumerable<T>.
У класу List<T> є наступні конструктори.
public List()
public List(IEnumerable<T> collection) public List(int capacity)
Перший конструктор створює порожню колекцію класу List з обираної за замовчуванням первісною ємністю. Другий конструктор створює колекцію типу List з кількістю ініціалізуючих елементів, що визначається параметром collection і дорівнює первісної ємності масиву. Третій конструктор створює колекцію типу List, що має первісну ємність, що задає параметром capacity. У цьому випадку ємність позначає розмір базового масиву, використовуваного для зберігання елементів колекції. Ємність колекції, створюваної у вигляді динамічного масиву, може збільшуватися автоматично в міру додавання в неї елементів.
У класі List<T> визначається ряд власних методів, крім тих, що вже оголошено в інтерфейсах, які в ньому реалізуються. Деякі з найбільше часто використовуваних методів цього класу перераховані в табл. 25.15.
Таблиця 25.15. Найбільше часто використовувані методи, певні в класі List<T>
Метод |
Опис |
public virtual void AddRange(Icollection . collection) |
Додає елементи з колекції collection у кінець зухвалої колекції типу ArrayList |
public virtual int BinarySearch(T item) |
Виконує пошук у колекції значення, що задає параметром item. Повертає індекс елемента, що збігся. Якщо шукане значення не знайдене, повертається негативне значення. Список повинен бути відсортований |
public int BinarySearch(Т item, IComparer<T> comparer) |
Виконує пошук у колекції значення, що задає параметром item, використовуючи для порівняння зазначений спосіб, обумовлений параметром comparer. Повертає індекс елемента, що збігся. Якщо шукане значення не знайдене, повертається негативне значення. Список повинен бути відсортований |
public int BinarySearch (int index, int count, T item, IComparer<T> comparer) |
Виконує пошук у колекції значення, що задає параметром item, використовуючи для порівняння зазначений спосіб, обумовлений параметром comparer. Пошук починається з елемента, що вказує по індексі index, і включає кількість елементів, обумовлених параметром count. Метод повертає індекс елемента, що збігся. Якщо шукане значення не знайдене, повертається негативне значення. Список повинен бути відсортований |
public List<T> GetRange(int index, int count) |
Повертає частина зухвалої колекції. Частина повертає коллекции, що, починається з елемента, що вказує по індексі index, і включає кількість елементів, що задає параметром count. Об'єкт, що повертає, посилається на ті ж елементи, що й зухвалий об'єкт |
public int IndexOf(T item) |
Повертає індекс першого входження елемента i tem у зухвалій колекції. Якщо шуканий елемент не виявлений, повертається значення -1 |
public void InsertRange(int index, IEnumerable<T> collection)
|
Вставляє елементи колекції collection у зухвалу колекцію, починаючи з елемента, що вказує по індексі index |
public int LastlndexOf(T item)
|
Повертає індекс останнього входження елемента item у зухвалій колекції. Якщо шуканий елемент не виявлений, повертається значення -1 |
public void RemoveRange(int index, int count)
|
Видаляє частину зухвалої колекції, починаючи з елемента, що вказує по індексі index, і включаючи кількість елементів, обумовлена параметром count |
public void Reverse() |
Розташовує елемент зухвалої колекції у зворотному порядку |
pufolic void Reverse(int index, int count)
|
Розташовує у зворотному порядку частина зухвалої колекції, починаючи з елемента, що вказує по індексі index, і включаючи кількість елементів, обумовлена параметром count Сортує зухвалу колекцію по наростаючо |
public void Sort(IComparision<Т>)
|
Сортує колекцію, використовуючи для порівняння спосіб, що задає параметром comparer. Якщо параметр comparer має порожнє значення, то для порівняння використається спосіб, обираний за замовчуванням |
public void Sort(Comparison<T> comparison) |
Сортує колекцію, використовуючи для порівняння зазначений делегат |
public void Sort(int index, int count, IComparer<T> comparer) |
Сортує зухвалу колекцію, використовуючи для порівняння спосіб, що задає параметром comparer. Сортування починається з елемента, що вказує по індексі index, і включає кількість елементів, обумовлених параметром count. Якщо параметр comparer має порожнє значення, то для порівняння використається спосіб, обираний за замовчуванням |
public T[] ToArray() |
Повертає масив, що містить копії елементів зухвалого об'єкта |
public void TrimExcess() |
Скорочує ємність колекції таким чином, щоб вона не перевищувала 10% від кількості елементів, що зберігаються в ній на даний момент |
У класі List<T> визначається також власна властивість Capacity, крім тих, що вже оголошено в інтерфейсах, які в ньому реалізуються. Ця властивість оголошується в такий спосіб.
public int Capacity { get; set; }
Властивість Capacity дозволяє встановити й одержати ємність зухвалої колекції як динамічний масив. Ця ємність дорівнює кількості елементів, які може містити колекція до її змушеного розширення. Така колекція розширюється автоматично, і тому задавати її ємність вручну необов'язково. Але з міркувань ефективності це іноді можна зробити, якщо заздалегідь відома кількість елементів колекції. Завдяки цьому виключаються витрати на виділення додаткової пам'яті.
У класі List<T> реалізується також наведений нижче індексатор, певний в інтерфейсі IList<T>.
public Т this[int index] { get; set; }
За допомогою цього індексатора встановлюється й виходить значення елемента колекції, що вказує по індексі index.
У наведеному нижче прикладі програми демонструється застосування класу List<T>. Це змінений варіант приклада, що демонстрировали раніше клас ArrayList. Єдина зміна, що треба було для цього, полягало в заміні класу ArrayList класом List, а також у використанні параметрів узагальненого типу.
// Продемонструвати застосування класу List<T>. using System;
using System.Collections.Generic;
class GenListDemo { static void Main() {
II Створити колекцію у вигляді динамічного масиву.
List<char> 1st = new List<char>();
Console.WriteLine("Вихідна кількість елементів: " + 1st.Count);
Console.WriteLine();
Console.WriteLine("Додати 6 елементів");
// Додати елементи в динамічний масив.
1st.Add('С'); lst.Add('А'); lst.Add('E');
1st.Add('В1);
1st.Add('D');
1st.Add('F');
Console.WriteLine("Кількість елементів: " + 1st.Count);
// Відобразити вміст динамічного масиву,
// використовуючи індексування масиву.
Console.Write("Поточний вміст: "); for (int i=0; i < 1st.Count;. i++)
Console.Write(1st[i] + " ");
Console.WriteLine("\n");
Console.WriteLine("Видалити 2 елементи ");
// Видалити елементи з динамічного масиву.
1st.Remove('F');
1st.Remove('А');
Console.WriteLine("Кількість елементів: " + 1st.Count);
// Відобразити вміст динамічного масиву, використовуючи цикл foreach. Console.Write("Вміст: "); foreach(char з in 1st)
Console.Write(з + " ");
Console.WriteLine("\n");
Console.WriteLine("Додати ще 20 елементів");
// Додати кількість елементів, достатнє для // примусового розширення масиву, for(int i=0; i < 20; i++) lst.Add((char)('a' + i));
Console.WriteLine("Поточна ємність: " + 1st.Capacity);
Console.WriteLine("Кількість елементів після додавання 20 нових: " + 1st.Count);
Console.Write("Уміст: ");
foreach(char з in 1st)
Console.Write(з + " ");
Console.WriteLine("\n");
// Змінити вміст динамічного масиву,
//' використовуючи індексування масиву.
Console.WriteLine("Змінити три перших елементи");
1st [0] = 'X';
1st[1] = 1Y1 ;
1st[2] = ' Z1 ;
Console.Write("Уміст: "); foreach(char c in 1st)
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<T>
У класі LinkedList<T> створюється колекція у вигляді узагальненого двунаправленного списку. У цьому класі реалізуються інтерфейси ICollection, ICollection<T>, IEnumerable, IEnumerable<T>, ISerializable і IDeserializationCallback. У двох останніх інтерфейсах підтримується сериализация списку. У класі LinkedList<T> визначаються два наведених нижче відкритих конструктори.
public LinkedList
public LinkedList(IEnumerable<T> collection)
У першому конструкторі створюється порожній зв'язний список, а в другому конструкторі — список, инициализируемый елементами з колекції collection.
Як й у більшості інших реалізацій зв'язних списків, у класі LinkedList<T> інкапсулюються значення, що зберігаються у вузлах списку, де перебувають також посилання на попередні й наступні елементи списку. Ці вузли являють собою обєкти класу LinkedListNode<T>. У класі LinkedListNode<T> надаються чотири наступні властивості.
public LinkedListNode<T> Next { get; )
public LinkedListNode<T> Previous { get; }
public LinkedList<T> List { get; }
public T Value { get; set; }
За допомогою властивостей Next і Previous виходять посилання на попередній і наступний вузли списку відповідно, що дає можливість обходити список в обох напрямках. Якщо ж попередній або наступний вузол відсутній, то повертається порожнє посилання. Для одержання посилання на сам список служить властивість List. А за допомогою властивості Value можна встановлювати й одержувати значення, що перебуває у вузлі списку.
У класі LinkedList<T> визначається чимало методів. У табл. 25.16 наведені найбільше часто використовувані методи даного класу. Крім того, у класі LinkedList<T> визначаються власні властивості, крім тих, що вже оголошено в інтерфейсах, які в ньому реалізуються. Ці властивості наведені нижче.
public LinkedListNode<T> First { get; }
public LinkedListNode<T> Last { get; }
За допомогою властивості First виходить перший вузол у списку, а за допомогою властивості Last - останній вузол у списку.
Таблиця 25.16. Найбільше часто використовувані методи, певні в класі
LinkedList<T>
Метод |
Опис |
public LinkedListNode<T> AddAfter(LinkedListNode<T> node, T value) |
Додає в список вузол зі значенням value безпосередньо після зазначеного вузла node. Вузол, що вказує, node не повинен бути порожнім (null). Метод повертає посилання на вузол, що містить значення value |
public void AddAfter(LinkedListNode<T> node, LinkedListNode<T> newNode)
|
Додає в список новий вузол newNode безпосередньо після зазначеного вузла node. Вузол, що вказує, node не повинен бути порожнім (null). Якщо вузол node відсутній у списку або якщо новий вузол newNode є частиною іншого списку, то' генерується виключення InvalidOperationException |
public LinkedListNode<T> AddBefore(LinkedListNode<T> node, T value)
|
Додає в список вузол зі значенням value безпосередньо перед зазначеним вузлом node. Вузол, що вказує, node не повинен бути порожнім (null). Метод повертає посилання на вузол, що містить значення value |
public void AddBefore(LinkedListNode<T> node, LinkedListNode<T> newNode)
|
Додає в список новий вузол newNode безпосередньо перед зазначеним вузлом node. Вузол, що вказує, node не повинен бути порожнім (null). Якщо вузол node відсутній у списку або якщо новий вузол newNode є частиною іншого списку, то генерується виключення InvalidOperationException |
public LinkedList<T> AddFirst(T value)
|
Додає вузол зі значенням value у початок списку. Метод повертає посилання на вузол, що містить значення value |
public void AddFirst(LinkedListNode node)
|
Додає вузол node у початок списку. Якщо вузол node є частиною іншого списку, то генерується виключення InvalidOperationException |
public LinkedList<T> AddLast(T value)
|
Додає вузол зі значенням value у кінець списку. Метод повертає посилання на вузол, що містить значення value
|
public void AddLast(LinkedListNode node)
|
Додає вузол node у кінець списку. Якщо вузол node є частиною іншого списку, то генерується виключення InvalidOperationException |
public LinkedList<T> Find(T value)
|
Повертає посилання на перший вузол у списку, що має значення value. Якщо шукане значення value відсутній у списку, то повертається порожнє значення |
public LinkedList<T> FindLast(T value)
|
Повертає посилання на останній вузол у списку, що має значення value. Якщо шукане значення value відсутній у списку, то повертається порожнє значення |
public bool Remove(T value)
|
Видаляє зі списку перший вузол, що містить значення value. Повертає логічне значення true, якщо вузол вилучений, тобто якщо вузол зі значенням value виявлений у списку й вилучений; у противному випадку повертає логічне значення false |
public void Remove(LinkedList<T> node)
|
Видаляє зі списку вузол, що відповідає зазначеному вузлу node. Якщо вузол node відсутній у списку, то генерується виключення InvalidOperationException |
public void RemoveFirst() |
Видаляє зі списку перший вузол |
public void RemoveLast |
Видаляє зі списку останній вузол |
У наведеному нижче прикладі програми демонструється застосування класу LinkedList<T>.
// Продемонструвати застосування класу LinkedList<T>. using System;
using System.Collections.Generic;
class GenLinkedListDemo { static void Main() {
// Створити зв'язний список.
LinkedList<char> 11 = new LinkedList<char>();
Console.WriteLine("Вихідна кількість елементів у списку: " + 11.Count); Console.WriteLine ();
Console.WriteLine("Додати в список 5 елементів");
// Додати елементи у зв'язний список.
11.AddFirst('А');
11.AddFirst('В') ;
11.AddFirst(‘С');
11.AddFirst('D') ;
11.AddFirst ('Е');
Console.WriteLine("Кількість елементів у списку: " + 11.Count);
// Відобразити зв'язний список, обійшовши його вручну.
LinkedListNode<char> node;
Console.Write("Відобразити вміст списку по посиланнях: "); for(node = 11.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("Випливати по посиланнях у зворотному напрямку: "); for(node = 11.Last; node != null; node = node.Previous)
Console.Write(node.Value + " ");
Console.WriteLine("\n");
// Видалити зі списку два елементи.
Console.WriteLine("Видалити 2 елементи зі списку");
// Видалити елементи зі зв'язного списку.
11.Remove('С');
11.Remove ('А') ,*
Console.WriteLine("Кількість елементів у списку: " + 11.Count);
// Відобразити вміст видозміненого списку в циклі foreach.
Console.Write("Вміст списку після видалення елементів: "); foreach(char ch in 11)
Console.Write(ch + " ");
Console.WriteLine("\n");
// Додати три елементи в кінець списку.
11.AddLast('X'); ll.AddLast('Y');
11.AddLast CZ') ;
Console.Write("Вміст списку після уведення елементів: "); foreach(char ch in 11)
Console.Write(ch + " ");
Console.WriteLine("\n");
}
}
Нижче наведений результат виконання цієї програми.
Вихідна кількість елементів у списку : 0
Додати в список 5 елементів
Кількість елементів у списку : 5
Відобразити вміст списку по посиланнях: Е D С B А
Відобразити вміст списку в циклі foreach: Е D С B А
Випливати по посиланнях у зворотному напрямку: А В С D Е
Видалити 2 елементи зі списку
Кількість елементів у списку: 3
Уміст списку після видалення елементів: Е D У
Уміст списку після уведення елементів: Е D У X Y Z
Саме примітне в цій програмі - це обхід списку в прямому й зворотному напрямку, випливаючи по посиланнях, надаваним властивостями Next і Previous. Двунаправленный характер подібних зв'язних списків має особливе значення для додатків, що управляють базами даних, де нерідко потрібно переміщатися за списком в обох напрямках.
Клас Dictionary<TKey, TValue>
Клас Dictionary<TKey, TValue> дозволяє зберігати пари "джерело-значення" у колекції як у словнику. Значення доступні в словнику по відповідних ключах. Щодо цього даний клас аналогічний неузагальненому класу Hashtable. У класі Dictionary<TKey, TValue> реалізуються інтерфейси IDictionary, IDictionary<TKey, TValue>, ICollection, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable, IEnumerable<KeyValuePair<TKey, TValue>>, ISerializable й IDeserializationCallback. У двох останніх інтерфейсах підтримується серіалізація списку. Словники мають динамічний характер, розширюючись у міру необхідності.
В класі Dictionary<TKey, TValue> надається чимало конструкторів. Нижче перераховані найбільше часто використовувані з них.
public Dictionary()
public Dictionary(IDictionary<TKey, TValue> dictionary)
public Dictionary(int capacity)
У першому конструкторі створюється порожній словник з обираної за замовчуванням первісною ємністю. У другому конструкторі створюється словник із зазначеною кількістю елементів dictionary. А в третьому конструкторі за допомогою параметра capacity указується ємність колекції, створюваної у вигляді словника. Якщо розмір словника заздалегідь відомий, те, указавши ємність створюваної колекції, можна виключити зміна розміру словника під час виконання, що, як правило, вимагає додаткових витрат обчислювальних ресурсів.
У класі Dictionary<TKey, TValue> визначається також ряд методів. Деякі найбільше часто використовувані методи цього класу зведені в табл. 25.17.
Таблиця 25.17. Найбільше часто використовувані методи, певні в класі Dictionary<TKey, TValue>
Метод |
Опис |
public value void Add (TKey key, TValue) |
Додає в словник пари "джерело-значення", обумовлену параметрами key й value. Якщо ключ key уже перебуває в словнику, то його значення не змінюється, і генерується виключення ArgumentException bool ContainsKey |
Public bool ContainsValue (TKey, key) |
Повертає логічне значення true, якщо словник містить об'єкт key як ключ; а інакше - логічне значення false |
Public bool ContainsValue (TValue, value) |
Повертає логічне значення true, якщо словник містить значення value; у противному випадку — логічне значення false |
public bool Remove(TKey key) |
Видаляє ключ key зі словника. При вдалому результаті операції повертається логічне значення true, а якщо ключ key відсутній у словнику — логічне значення false |
Варто мати на увазі, що ключі й значення, що втримуються в колекції, доступні окремими списками за допомогою властивостей Keys і Values. У колекціях типу Dictionary<TKey, TValue>.KeyCollectionи Dictionary<TKey, TValue>. ValueCollection реалізуються як узагальнені, так і неузагальнені форми інтерфейсів ICollection і IEnumerable.
І нарешті, у класі Dictionary<TKey, TValue> реалізується наведений нижче індексатор, певний в інтерфейсі IDictionary<TKey, TValue>
public TValue this[TKey key] { get; set; )
Цей індексатор служить для одержання й установки значення елемента колекції, а також для додавання в колекцію нового елемента. Але як індекс у цьому випадку служить ключ елемента, а не сам індекс.
При перерахуванні колекції типу Dictionary<TKey, TValue> з її повертаються пари "джерело-значення" у формі структури KeyValuePair<TKey, TValue> Нагадаємо, що в цій структурі визначаються два поля.
public TKey Key; public TValue Value;
У цих полях утримується ключ або значення відповідного елемента колекції. Як правило, структура KeyValuePair<TKey, TValue> не використається безпосередньо, оскільки засобу класу Dictionary<TKey, TValue> дозволяють працювати із ключами й значеннями окремо. Але при перерахуванні колекції типу Dictionary<TKey, TValue>, наприклад, у циклі foreach перераховують объектами, що, є пари типу Key Value Pair.
Всі ключі в колекції типу Dictionary<TKey, TValue> повинні бути унікальними, причому ключ не повинен змінюватися доти, поки він служить як ключ. У той же час значення не обов'язково повинні бути унікальними. До того ж об'єкти не зберігаються в колекції типу Dictionary<TKey, TValue> у відсортованому порядку.
У наведеному нижче прикладі демонструється застосування класу
Dictionary<TKey, TValue>
// Продемонструвати застосування класу узагальненої
// колекції Dictionary<TKey, TValue>.
using System;
using System.Collections.Generic;
class GenDictionaryDemo { static void Main() {
// Створити словник для зберігання імен і прізвищ
// працівників й їхньої зарплати.
Dictionary<string, double> diet =
new Dictionary<string, double>();
// Додати елементи в колекцію, diet.Add("Батлер, Джон", 73000); diet.Add("Шварц, Capa", 59000); diet.Add("Пайк, Томас", 45000) ; diet.Add("Фрэнк, Эд", 99000);
// Одержати колекцію ключів, тобто прізвищ й імен.
ICollection<string> з = diet.Keys;
// Використати ключі для одержання значень, тобто зарплати, foreach(string str in с)
Console.WriteLine("{0}, зарплата: {1:C}", str, diet[str]);
}
Нижче наведений результат виконання цієї програми.
Батлер, Джон, зарплата: $73,000.00
Шварц, Сара, зарплата: $59,000.00
Пайк, Томас, зарплата: $45,000.00
Фрэнк, Эд, зарплата: $99,000.00
Клас SortedDictionary<TKey, TValue>
У колекції класу SortedDictionary<TKey, TValue> пари "джерело-значення" зберігаються в такий же спосіб, як й у колекції класу Dictionary<TKey, TValue>, за винятком того, що вони відсортовані по відповідному ключі. У класі SortedDictionary<TKey, TValue> реалізуються інтерфейси IDictionary, IDictionarycTKey, TValue>,ICollection, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable і IEnumerable<KeyValuePair<TKey, TValue>>. У класі SortedDictionary<TKey, TValue> надаються також наступні конструктори.
public SortedDictionary()
public SortedDictionary(IDictionarycTKey, TValue> dictionary)
public SortedDictionary(IComparer<TKey> comparer)
public SortedDictionary(IDictionarycTKey, TValue> dictionary,
IComparer<TKey> comparer)
У першому конструкторі створюється порожній словник, у другому конструкторі - словник із зазначеною кількістю елементів dictionary. У третьому конструкторі допускається вказувати за допомогою параметра comparer типу IComparer спосіб порівняння, використовуваний для сортування, а в четвертому конструкторі - инициализировать словник, крім вказівки способу порівняння.
У класі SortedDictionary<TKey, TValue> визначений ряд методів. Деякі найбільше часто використовувані методи цього класу зведені в табл. 25.18.
Таблиця 25.18. Найбільше часто використовувані методи, певні в класі SortedDictionary<TKey, TValue>
Метод |
Опис |
public void Add (ТКеу key, TValue value) |
Додає в словник пари "джерело-значення”, обумовлену параметрами key й value. Якщо ключ key уже перебуває в словнику, те його значення не змінюється, і генерується виключення ArgumentException |
public bool ContainsKey (ТКеу, кеу) |
Повертає логічне значення true, якщо визивающий словник містить об'єкт key у якості ключа; у зворотньому випадку — логічне значення false |
public bool ContainsValue(TValue value) |
Повертає логічне значення true, якщо словник містить значення value, у противному випадку — логічне значення false |
public bool Remove(TKey key) |
Видаляє ключ key зі словника. При вдалому результаті операції повертається логічне значення true, а якщо ключ key відсутній у словнику — логічне значення false |
Крім того, у класі SortedDictionary<TKey, TValue> визначаються власні властивості, крім тих, що вже оголошено в інтерфейсах, які в ньому реалізуються. Ці властивості наведені нижче.
Варто мати на увазі, що ключі й значення, що втримуються в колекції, доступні окремими списками за допомогою властивостей Keys й Values. У колекціях типу SortedDictionary<TKey, TValue>.KeyCollection і SortedDictionary<TKey, TValue>. ValueCollection реалізуються як узагальнені, так і неузагальнені форми интерфейсовICollection иIEnumerable.
І нарешті, у класі SortedDictionary<TKey, TValue> реалізується наведений нижче індексатор, певний в інтерфейсі IDictionary<TKey, TValue>
public TValue this[TKey key] { get; set; }
Цей індексатор служить для одержання й установки значення елемента колекції, а також для додавання в колекцію нового елемента. Але в цьому випадку як індекс служить ключ елемента, а не сам індекс.
При перерахуванні колекції типу SortedDictionary<TKey, TValue> з її повертаються пари "джерело-значення" у формі структури KeyValuePairCTKey, TValue Нагадаємо, що в цій структурі визначаються два наступні поля.
public TKey Key; public TValue Value;
У цих полях утримується ключ або значення відповідного елемента колекції. Як правило, структура KeyValuePair<TKey, TValue> не використається безпосередньо, оскільки засобу класу SortedDictionary<TKey, TValue> дозволяють працювати із ключами й значеннями окремо. Але при перерахуванні колекції типу SortedDictionary<TKey, TValue> наприклад у циклі foreach, що перераховують об'єктами є пари типу KeyValuePair.
Всі ключі в колекції типу SortedDictionary<TKey, TValue> повинні бути унікальними, причому ключ не повинен змінюватися доти, поки він служить як ключ. У той же час значення не обов'язково повинні бути унікальними.
У наведеному нижче прикладі демонструється застосування класу SortedDictionaryCTKey, TValue Це змінений варіант попереднього приклада, що демонстрував застосування класу Dictionary<TKey, TValue> У даному варіанті база даних працівників відсортована на прізвище й ім'я працівника, які служать як ключ.
// Продемонструвати застосування класу узагальненої // колекції SortedDictionary<TKey, TValue>.
using System;
using System.Collections.Generic;
class GenSortedDictionaryDemo { static void Main() {
// Створити словник для зберігання імен і прізвищ // працівників й їхньої зарплати.
SortedDictionary<string, double> diet =
new SortedDictionaryCstring, double>();
// Додати елементи в колекцію, diet.Add("Батлер, Джон", 73000); diet.Add("Шварц, Capa", 59000); diet.Add("Пайк, Томас", 45000); diet.Add("Фрэнк, Эд", 99000);
// Одержати колекцію ключів, тобто прізвищ й імен.
ICollection<string> з = diet.Keys;
// Використати ключі для одержання значень, тобто зарплати, foreach(string str in с)
Console.WriteLine("{0}, зарплата: {1:C}", str, dictfstr]);
}
Ця програма дає наступний результат.
Батлер, Джон, зарплата: $73,000.00
Пайк, Томас, зарплата: $45,000.00
Фрэнк, Эд, зарплата: $99,000.00
Шварц, Сара, зарплата: $59,000.00
Як бачите, список працівників й їхніх зарплат відсортовані по ключі, у якості якого в цьому випадку служить прізвище й ім'я працівника.
Клас SortedList<TKey, TValue>
У колекції класу SortedList<TKey, TValue> зберігається відсортований список пар "джерело-значення". Це узагальнений еквівалент класу неузагальненої колекції SortedList. У класі SortedList<TKey, TValue> реалізуються інтерфейси IDictionary, IDictionary<TKey, TValue>,ICollection, ICollectionCKeyValuePair<TKey, TValue>, IEnumerable й IEnumerablecKeyValuePair<TKey, TValue>. Розмір колекції типу SortedList<TKey, TValue> змінюється динамічно, автоматично збільшуючись у міру необхідності. Клас SortedList<TKey, TValue> подібний до класу SortedDictionary<TKey, TValue>, але в нього інші робочі характеристики. Зокрема, клас SortedList<TKey, TValue> використає менше пам'яті, тоді як клас SortedDictionary<TKey, TValue> дозволяє швидше вставляти неупорядковані елементи в колекцію.
У класі SortedList<TKey, TValue> надається чимало конструкторів. Нижче перераховані найбільше часто використовувані конструктори цього класу.
public SortedList()
public SortedList(IDictionary<TKey, TValue> dictionary)
public SortedList(int capacity)
public SortedList(IComparer<TK> comparer)
У першій формі конструктора створюється порожній список з обираної за замовчуванням первісною ємністю. У другій формі конструктора створюється відсортований список із зазначеною кількістю елементів dictionary. У третій формі конструктора за допомогою параметра capacity задається ємність колекції, створюваної у вигляді відсортованого списку. Якщо розмір списку заздалегідь відомий, указавши ємність створюваної колекції, можна виключити зміна розміру списку під час виконання, що, як правило, вимагає додаткових витрат обчислювальних ресурсів. І в четвертій формі конструктора допускається вказувати за допомогою параметра comparer спосіб порівняння об'єктів, що втримуються в списку.
Ємність колекції типу SortedList<TKey, TValue> збільшується автоматично в міру необхідності, коли в список додаються нові елементи. Якщо поточна ємність колекції перевищується, то вона збільшується. Перевага вказівки ємності колекції типу SortedList<TKey, TValue> при її створенні полягає в зниженні або повнім виключенні витрат на зміну розміру колекції. Зрозуміло, указувати ємність колекції доцільно лише в тому випадку, якщо заздалегідь відомо, скільки елементів потрібно зберігати в ній.
У класі SortedList<TKey, TValue> визначається ряд власних методів, крім тих, що вже оголошено в інтерфейсах, які в ньому реалізуються. Деякі з найбільше часто використовуваних методів цього класу перераховані в табл. 25.19. Варто мати на увазі, що перечисельник, що повертає методом GetEnumerator ( ), служить для перерахування пар "джерело-значення", що зберігаються у відсортованому списку у вигляді об'єктів типу KeyValuePair.
Таблиця 25.19. Найбільше часто використовувані методи, певні в класі SortedListcTKey, TValue>
Метод |
Опис |
public void Add (TKey key, TValue value) |
Додає в список пари “джерело-значення”,обумовлену параметрами кеу й value. Якщо ключ кеу вже перебуває в списку, то його значення не змінюється, і генерується виключення ArgumentException |
public bool ContainsKey (ТК кеу) |
Повертає логічне значення true, якщо список містить об'єкт кеу як ключ; а інакше -логічне значення false |
public bool ContainsValue(TValue value)
|
Повертає логічне значення true, якщо список містить значення value; у противному випадку - логічне значення false
|
public IEnumerator<KeyValuePair <TKey, TValue>> GetEnumerator() |
Повертає перечисельник для словника
|
public int IndexOfKey(TKey key)
|
Повертає індекс ключа key. Якщо шуканий ключ не виявлений у списку, повертається значення -1
|
public int IndexOfValue(TValue value)
|
Повертає індекс першого входження значення value у списку. Якщо шукане значення не виявлене в списку, повертається значення -1 |
public bool Remove(TKey key)
|
Видаляє зі списку пари "джерело-значення” по зазначеному ключі key. При вдалому результаті операції повертається логічне значення true, а якщо ключ key відсутній у списку — логічне значення false |
public void RemoveAt(int index) public void TrimExcess
|
Видаляє зі списку пари "джерело-значення” по зазначеному індексі index Скорочує надлишкову ємність колекції у вигляді відсортованого списку |
Крім того, у класі SortedList<TK, визначаються власні властивості, крім тих, що вже
оголошено в інтерфейсах, які в ньому реалізуються. Ці властивості наведені нижче.
Властивості |
Опис |
public int Capacity { get; set; }
|
Одержує або встановлює ємність колекції у вигляді відсортованого списку |
public IComparer<TK> Comparer { get; } |
Одержує метод порівняння для списку |
public IList<TK> Keys { get; } public IList<TV> Values { get; }
|
Одержує колекцію ключів Одержує колекцію значень |
І нарешті, у класі SortedList<TKey, TValue> реалізується наведений нижче індексатор, певний в інтерфейсі IDictionary<TKey, TValue>
public TValue this [TKey key] { get; set; }
Цей індексатор служить для одержання й установки значення елемента колекції, а також для додавання в колекцію нового елемента. Але в цьому випадку як індекс служить ключ елемента, а не сам індекс.
У наведеному нижче прикладі демонструється застосування класу SortedList<TKey, TValue> Це ще один змінений варіант представленого раніше приклада бази даних працівників. У даному варіанті база даних зберігається в колекції типу SortedList.
// Продемонструвати застосування класу узагальненої // колекції SortedList<TKey, TValue>.
using System;
using System.Collections.Generic;
class GenSLDemo {
static void Main() {
// Створити колекцію у вигляді відсортованого списку // для зберігання імен і прізвищ працівників й їхніх зарплат.
SortedList<string, double> si =
new SortedList<string, double>();
// Додати елементи в колекцію, si.Add("Батлер, Джон", 73000); si.Add("Шварц, Сара", 59000); sl.Add("Пaйк, Томас", 45000); si.Add("Фрэнк, Эд", 99000);
// Одержати колекцію ключів, тобто прізвищ й імен.
ICollection<string> з = sl.Keys;
// Використати ключі для одержання значень, тобто зарплати, foreach(string str in с)
Console.WriteLine("{0), зарплата: {1:C}", str, slfstr]);
Console.WriteLine();
}
Нижче наведений результат виконання цієї програми.
Батлер, Джон, зарплата: $73,000.00
Пайк, Томас, зарплата: $45,000.00
Фрэнк, Эд, зарплата: $99,000.00
Шварц, Сара, зарплата: $59,000.00
Як бачите, список працівників й їхніх зарплат відсортовані по ключі, у якості якого в цьому випадку служить прізвище й ім'я працівника.
Клас Stack<T>
Клас Stack<T> є узагальненим еквівалентом класу неузагальненої колекції Stack. У ньому підтримується стек у вигляді списку, що діє за принципом "першим прийшов — останнім обслужений". У цьому класі реалізуються інтерфейси Collection, IEnumerable й IEnumerable<T>. Крім того, у класі Stack<T> безпосередньо реалізуються методи Clear ( ), Contains ( ) і СоруТо ( ), певні в інтерфейсі ICollection<T>. А методи Add ( ) і Remove ( ) у цьому класі не підтримуються, як, втім, і властивість IsReadOnly. Колекція класу Stack<T> має динамічний характер, розширюючись у міру необхідності, щоб умістити всі елементи, які повинні в ній зберігатися. У класі Stack<T> визначаються наступні конструктори.
public Stack()
public Stack(int capacity)
public Stack(IEnumerable<T> collection)
У першій формі конструктора створюється порожній стек з обираної за замовчуванням первісною ємністю, а в другій формі - порожній стік, первісний розмір якого визначає параметр capacity. І в третій формі створюється стек, що містить елементи колекції, обумовленої параметром collection. Його первісна ємність дорівнює кількості зазначених елементів.
У класі Stack<T> визначається ряд власних методів, крім тих, що вже оголошено в інтерфейсах, які в ньому реалізуються, а також в інтерфейсі ICollection<T>. Деякі з найбільше часто використовуваних методів цього класу перераховані в табл. 25.20. Як й у класі Stack, ці методи звичайно застосовуються в такий спосіб. Для того щоб помістити об'єкт на вершині стека, викликається метод Push (). А для того щоб витягти й видалити об'єкт із вершини стека, викликається метод Pop (). Якщо ж об'єкт потрібно тільки витягти, але не видалити з вершини стека, то викликається метод Peek (). А якщо викликати метод Pop () або Peek (), коли зухвалий стік порожній, то згенерується виключення InvalidOperationException.
Таблиця 25.20. Методи, певні в класі Stack<T>
Метод |
Опис |
public Т Peek () |
Повертає елемент, що перебуває на вершині стека, але не видаляє його |
public T Pop ()
|
Повертає елемент, що перебуває на вершині стека, видаляючи його в процесі роботи |
public void Push(T item) |
Поміщає елемент item у стек |
public T[] ToArray |
Повертає масив, що містить копії елементів визивающого стека |
public void TrimExcess () |
Скорочує надлишкову ємність колекції у вигляді стека |
У наведеному нижче прикладі програми демонструється застосування класу Stack<T>.
// Продемонструвати застосування класу Stack<T>. using System;
using System.Collections.Generic;
class GenStackDemo { static void Main() {
Stack<string> st = new Stack<string>();
st.Push("один");
st.Push("два");
st.Push("три");
st.Push("чотири");
st.Push(“п’ять") ;
while(st.Count > 0) { string str = st.Pop();
Console.Write(str + " ");
}
Console.WriteLine(); '
}
)
При виконанні цієї програми виходить наступний результат, п'ять чотири три два один
Клас Queue<T>
Клас Queue<T> є узагальненим еквівалентом класу неузагальненої колекції Queue. У ньому підтримується черга у вигляді списку, що діє за принципом "першим прийшов - першим обслужений". У цьому класі реалізуються інтерфейси ICollection, IEnumerable і IEnumerable<T>. Крім того, у класі Queue<T> безпосередньо реалізуються методи Clear (), Contains () і Соруто (), певні в інтерфейсі ICollection<T>. А методи Add () і Remove () у цьому класі не підтримуються, як, втім, і властивість IsReadOnly. Колекція класу Queue<T> має динамічний характер, розширюючись у міру необхідності, щоб умістити всі елементи, які повинні зберігатися в ній. У класі Queue<T> визначаються наступні конструктори.
public Queue()
public Queue(int capacity)
public Queue(IEnumerable<T> collection)
У першій формі конструктора створюється порожня черга з обираної за замовчуванням первісною ємністю, а в другій формі - порожня черга, первісний розмір якої визначає параметр capacitу. І в третій формі створюється черга, що містить елементи колекції, обумовленої параметром collection. Її первісна ємність дорівнює кількості зазначених елементів.
У класі Queue<T> визначається ряд власних методів, крім тих, що вже оголошено в інтерфейсах, які в ньому реалізуються, а також в інтерфейсі ICollection<T>. Деякі з найбільше часто використовуваних методів цього класу перераховані в табл. 25.21. Як й у класі Queue, ці методи звичайно застосовуються в такий спосіб. Для того щоб помістити об'єкт у чергу, викликається метод Enqueue (). Якщо потрібно витягти й видалити перший об'єкт із початку черги, то викликається метод Dequeue (). Якщо ж потрібно витягти, але не видаляти наступний об'єкт із черги, то викликається метод Peek(). А якщо методи Dequeue () і Peek () викликаються, коли черга порожня, то генерується виключення InvalidOperationException.
Таблиця 25.21. Методи, певні в класі Queue<T>
Метод |
Опис |
Public Т Dequeue () |
Повертає об'єкт із початку зухвалої черги. Об'єкт, що повертає, віддаляється із черги |
Public void Enqueue(T item) |
Додає елемент item у кінець черги |
Public T Peek() |
Повертає елемент із початку зухвалої черги, але не видаляє його |
public virtual Т[] ToArray()
|
Повертає масив, що містить копії елементів із зухвалої черги |
public void TrimExcess |
Скорочує надлишкову ємність зухвалої колекції у вигляді черги |
У наведеному нижче прикладі демонструється застосування класу Queue<T>.
// Продемонструвати застосування класу Queue<T>. using System;
using System.Collections.Generic;
class GenQueueDemo { static void Main() {
Queue<double> q = new Queue<double>();
q.Enqueue(98.6);
q.Enqueue(212.0);
q.Enqueue(32.0);
q.Enqueue(3.1416);
double sum = 0.0;
Console.Write("Черга містить: "); while(q.Count > 0) {
double val = q.Dequeue();
Console.Write(val + " "); sum += val;.
}
Console.WriteLine("Хпитоговая сума дорівнює " + sum);
}
От до якого результату приводить виконання цієї програми.
Черга містить: 98.6 212 32 3.1416
Підсумкова сума дорівнює 345.7416
Клас HashSet<T>
У класі HashSet<T> підтримується колекція, що реалізує безліч. Для зберігання елементів цієї безлічі в ньому використається хеш-таблица. У класі HashSet<T> реалізуються інтерфейси ICollection<T>, ISet<T>, IEnumerable, IEnumerable<T>, ISerializable, a також IDeserializationCallback. У колекції типу HashSet<T> реалізується безліч, всі елементи якого є унікальними. Іншими словами, дублікати в такій безлічі не допускаються. Порядок проходження елементів у безлічі не вказується. У класі HashSet<T> визначається повний набір операцій з безліччю, певних в інтерфейсі Iset<T>, включаючи перетинання, об'єднання й разноименность. Завдяки цьому клас HashSet<T> виявляється ідеальним засобом для роботи з безлічами об'єктів, коли порядок розташування елементів у безлічі особливого значення не має. Колекція типу
HashSet<T> має динамічний характер і розширюється в міру необхідності, щоб умістити всі елементи, які повинні в ній зберігатися.
Нижче перераховані найбільш уживані конструктори, певні в класі HashSet<T>.
public HashSet()
public HashSet(IEnumerable<T> collection)
public HashSet(IEqualityCompare comparer)
public HashSet(IEnumerable<T> collection, IEqualityCompare comparer)
У першій формі конструктора створюється порожня безліч, а в другій формі - безліч, що складається з елементів указує коллекции, що, collection. У третій формі конструктора допускається вказувати спосіб порівняння за допомогою параметра comparer. А в четвертій формі створюється безліч, що складається з елементів указує коллекции, що, collection, і використається заданий спосіб порівняння comparer. Є також п'ята форма конструктора даного класу, у якій допускається инициализировать безліч послідовно впорядкованими даними.
У класі HashSet<T> реалізується інтерфейс ISet<T>, а отже, у ньому надається повний набір операцій з безлічами. У цьому класі надається також метод RemoveWhere (), що видаляє з безлічі елементи, що не задовольняють заданій умові, або предикату.
Крім властивостей, певних в інтерфейсах, які реалізуються в класі HashSet<T>, у нього уведене додаткова властивість Comparer, наведене нижче.
public IEqualityComparer<T> Comparer { get; }
Воно дозволяє одержувати метод порівняння для зухвалого хеш-множини.
Нижче наведений конкретний приклад застосування класу HashSet<T>.
// Продемонструвати застосування класу HashSet<T>. using System;
using System.Collections.Generic; class HashSetDemo {
static void Show(string msg, HashSet<char> set)
Console.Write(msg); foreach(char ch in set)
Console.Write(ch + " ");
Console.WriteLine ();
static void Main() {
HashSet<char> set = new HashSet<char>() HashSet<char> set = new HashSet<char>()
set.Add('A') set.Add('B')
set.Add(1С')
set.Add(' С'); set.Add CD');
set.Add('Е');
Show("Вихідний уміст безлічі set: ", set);
Show("Вихідний уміст безлічі set: ", set);
set.SymmetricExceptWith(set);
Show("Уміст безлічі set після " +
"разноименности з безліччю Set: ", set);
set.UnionWith(set);
Show("Уміст безлічі set після " +
"об'єднання з безліччю Set: ", set);
set.ExceptWith(set);
Show("Уміст безлічі set після " +
"вирахування з безлічі set: ", set);
Console.WriteLine();
}
Нижче наведений результат виконання програми з даного приклада.
Вихідний уміст безлічі set: ABC Вихідний уміст безлічі set: С D Е
Уміст безлічі set після разноименности з безліччю Set: А В D Е
Вміст безлічі set після об'єднання з безліччю Set: А В D Е С
Уміст безлічі set після вирахування з безлічі set: А В
Клас SortedSet<T>
Клас SortedSet<T> являє собою новий різновид колекції, уведену у версію 4.0 середовища .NET Framework. У ньому підтримується колекція, що реалізує відсортовану безліч. У класі SortedSet<T> реалізуються інтерфейси ISet<T>, ICollection, ICollection<T>, IEnumerable, IEnumerable<T>, ISerializable, а також IDeserializationCallback. У колекції типу SortedSet<T> реалізується безліч, всі елементи якого є унікальними. Іншими словами, дублікати в такій безлічі не допускаються. У класі SortedSet<T> визначається повний набір операцій з безліччю, певних в інтерфейсі ISet<T>, включаючи перетинання, об'єднання й разноименность. Завдяки тому що всі елементи колекції типу SortedSet<T> зберігаються у відсортованому порядку, клас SortedSet<T> виявляється ідеальним засобом для роботи з відсортованими безлічами об'єктів. Колекція типу SortedSet<T> має динамічний характер і розширюється в міру необхідності, щоб умістити всі елементи, які повинні в ній зберігатися.
Нижче перераховані чотири найбільше часто використовувані конструктори, певних у класі SortedSet<T>.
public SortedSet
public SortedSet(IEnumerable<T> collection)
public SortedSet(IComparer comparer)
public SortedSet(IEnumerable<T> collection, IComparer comparer)У першій формі конструктора створюється порожня безліч, а в другій формі - безліч, що складається з елементів указує коллекции, що, collection. У третій формі конструктора допускається вказувати спосіб порівняння за допомогою параметра comparer. А в четвертій формі створюється безліч, що складається з елементів указує коллекции, що, collection, і використається заданий спосіб порівняння comparer. Є також п'ята форма конструктора даного класу, у якій допускається инициализировать безліч послідовно впорядкованими даними.
У класі SortedSet<T> реалізується інтерфейс ISet<T>, а отже, у ньому надається повний набір операцій з безлічами. У цьому класі надається також метод GetViewBetween (), що повертає частину безлічі у формі об'єкта типу SortedSet<T>, метод RemoveWhere (), що видаляє з безлічі елементи, що не задовольняють заданій умові, або предикату, а також метод Reverse (), що повертає об'єкт типу IEnumerable<T>, що циклічно проходить безліч у зворотному порядку.
Крім властивостей, певних в інтерфейсах, які реалізуються в класі SortedSet<T>, у нього уведені додаткові властивості, наведені нижче, public IComparer<T> Comparer { get; } public T Max { get; } public T Min { get; }
Властивість Comparer одержує спосіб порівняння для зухвалої безлічі. Властивість Мах одержує найбільше значення в безлічі, а властивість Min - найменше значення в безлічі.
Як приклад застосування класу SortedSet<T> на практиці просто заміните позначення HashSet на SortedSet у вихідному коді програми з попереднього підрозділу, присвяченого колекціям типу HashSet<T>.
Паралельні колекції
У версію 4.0 середовища .NET Framework додане новий простір імен System. Collections .Concurrent. Воно містить колекції, які є потік безпеки й спеціально призначені для паралельного програмування. Це означає, що вони можуть безпечно використатися в многопоточной програмі, де можливий одночасний доступ до колекції з боку двох або більше, що виконують паралельно потоків. Нижче перераховані класи паралельних колекцій.
Паралельна колекція |
Опис |
BlockingCollection<T> |
Надає оболонку для реалізації, що блокує, інтерфейсу IProducerConsumerCollection<T> |
ConcurrentBag<T> |
Забезпечує неупорядковану реалізацію інтерфейсу IProducerConsumerCollection<T>, що виявляється найбільш придатної в тому випадку, коли інформація виробляється й споживається в одному потоці |
ConcurrentDictionary <TKey, TValue> |
Зберігає пари "значення^-значення-джерело-значення", а виходить, реалізує паралельний словник
|
ConcurrentQueue<T> |
Реалізує паралельну чергу й відповідний варіант інтерфейсу IProducerConsumerCollection<T>
|
ConcurrentStack<T> |
Реалізує паралельний стек і відповідний варіант ин- терфейса IproducerConsumerCollection<T> |
Як бачите, у декількох класах паралельних колекцій реалізується інтерфейс IProducerConsumerCollection. Цей інтерфейс також визначений у просторі імен System. Collections.Concurrent. Він служить як розширення інтерфейсів IEnumerable, IEnumerable<T> і ICollection. Крім того, у ньому визначені методи TryAdd () і TryTake(), що підтримують шаблон "постачальник- споживач". (Класичний шаблон "постачальник-споживач" відрізняється рішенням двох завдань. Перше завдання робить елементи колекції, а інша споживає їх.) Метод TryAdd () намагається додати елемент у колекцію, а метод TryTake() - видалити елемент із колекції. Нижче наведені форми оголошення обох методів.
bool TryAdd(Т item)
bool TryTake(out T item)
Метод TryAdd() повертає логічне значення true, якщо в колекцію доданий елемент i tern. А метод TryTake () повертає логічне значення true, якщо елемент item вилучений з колекції. Якщо метод TryAdd () виконаний успішно, то елемент iterm буде містити об'єкт. (Крім того, в інтерфейсі IProducerConsumerCollection указується перевантажує вариант, що, методу СоруTо (), обумовленого в інтерфейсі ICollection, а також методу Torray (), що копіює колекцію в масив.)
Паралельні колекції найчастіше застосовуються в комбінації з бібліотекою распараллеливания завдань (TPL) або мовою PLINQ. У силу особливого характеру цих колекцій всі їхні класи не будуть розглядатися далі докладно. Замість цього на конкретних прикладах буде даний короткий огляд класу BlockingCollection<T>. Засвоївши основи побудови класу BlockingCollection<T>, ви зможете без особливої праці розібратися й в інших класах паралельних колекцій.
У класі BlockingCollection<T>, власне кажучи, реалізується черга, що блокує. Це означає, що в такій черзі автоматично встановлюється очікування будь-яких спроб вставити елемент у колекцію, коли вона заповнена, а також спроб видалити елемент із колекції, коли вона порожня. Це ідеальне рішення для тих ситуацій, які пов'язані із застосуванням шаблона "постачальник-споживач". У класі BlockingCollection<T> реалізуються інтерфейси ICollection, IEnumerable, IEnumerable<T>, а також IDisposable.
У класі BlockingCollection<T> визначаються наступні конструктори.
public BlockingCollection()
public BlockingCollection(int boundedCapacity)
public BlockingCollection(IProducerConsumerCollection<T> collection)
public BlockingCollection(IProducerConsumerCollection<T> collection, int boundedCapacity)
У двох перших конструкторах в оболонку класу BlockingCollection<T> полягає колекція, що є екземпляром об'єкта типу ConcurrentQueue<T>. А у двох інших конструкторах можна вказати колекцію, що повинна бути покладена в основу колекції типу BlockingCollection<T>. Якщо вказується параметр boundedCapacitу, то він повинен містити максимальну кількість об'єктів, які колекція повинна містити перед тим, як вона виявиться заблокованою. Якщо ж параметр boundedCapacity не зазначений, то колекція виявляється необмеженою.
Крім методів TryAdd() і TryTake(), обумовлених паралельно з тими, що вказуються в інтерфейсі IProducerConsumerCollection<T>, у класі BlockingCollection<T> визначається також ряд власних методів. Нижче представлені методи, які будуть використатися в наведені далі прикладах.
public void Add(T item)
public T Take()
Коли метод Add() викликається для необмеженої колекції, він додає елемент item.B колекцію й потім повертає керування зухвалої частини програми. А коли метод Add() викликається для обмеженої колекції, він блокує доступ до неї, якщо вона заповнена. Після того як з колекції буде вилучені один елемент або більше, зазначений елемент item буде доданий у колекцію, і потім відбудеться повернення з даного методу. Метод Take() видаляє елемент із колекції й повертає керування зухвалої частини програми. (Є також варіанти обох методів, що приймають як параметр ознака завдання як екземпляр об'єкта типу CancellationToken.)
Застосовуючи методи Add() і Таке(), можна реалізувати простий шаблон "постачальник-споживач", як показано в наведеному нижче прикладі програми. У цій програмі створюється постачальник, що формує символи від А до Z, а також споживач, що одержує ці символи. При цьому створюється колекція типу BlockingCollection<T>, обмежена 4 елементами.
// Простий приклад колекції типу BlockingCollection. using System;
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Concurrent;
class BlockingDemo {
static BlockingCollection<char> be;
// Зробити й поставити символи від А до Z. static void Producer () { for(char ch = 'A'; ch <= 'Z'; ch++) { be.Add(ch);
Console.WriteLine ("Виробляється символ " + ch);
)
)
// Спожити 26 символів, static void Consumer () { for(int i=0; i < 26; i++)
Console .WriteLine ("Споживається символ " + bc.Take);
)
static void Main() {
// Використати колекцію, що блокує, обмежену 4 елементами, be = new BlockingCollection<char>(4);
// Створити завдання постачальника й споживача.
Task Prod = new Task(Producer);
Task Con = new Task(Consumer);
// Запустити завдання.
Con.Start();
Prod:Start();// Очікувати завершення обох завдань, try
{
Task.WaitAll(Con, Prod);
} catch(AggregateException exc) {
Console.WriteLine(exc) ;
} finally {
Con.Dispose() ;
Prod.Dispose() ; be.Dispose() ;
}
}
}
Якщо запустити цю програму на виконання, то на екрані з'явиться змішаний результат, виведений постачальником і споживачем. Почасти це порозумівається тим, що колекція Ьс обмежена 4 елементами, а це означає, що в неї може бути додано тільки чотири елементи, перш ніж її прийде скоротити. Як експеримент спробуйте зробити колекцію bc необмеженої й понаблюдайте за отриманими результатами. У деяких середовищах виконання це приведе до того, що всі елементи колекції будуть сформовані до того, як почнеться яке-небудь їхнє споживання. Крім того, спробуйте обмежити колекцію одним елементом. У цьому випадку одночасно може бути сформований лише один елемент.
Для роботи з колекцією типу BlockingCollection<T> може виявитися корисним і метод CompleteAdding (). Нижче наведена форма його оголошення.
public void CompleteAdding()
Виклик цього методу означає, що в колекцію не буде більше додано жодного елемента. Це приводить до того, що властивість IsAddingComplete приймає логічне значення true. Якщо ж колекція порожня, то властивість IsCompleted приймає логічне значення true, і в цьому випадку виклики методу Take() не блокуються. Нижче наведені форми оголошення властивостей IsAddingComplete і IsCompleted.
public bool IsCompleted { get; )
public bool IsAddingComplete { get; }
Коли колекція типу BlockingCollection<T> тільки починає формуватися, ці властивості містять логічне значення false. А після виклику методу CompleteAdding () вони приймають логічне значення true.
Нижче наведений варіант попереднього приклада програми, змінений з метою продемонструвати застосування методу CompleteAdding (), властивості IsCompleted і методу TryTake ().
// Застосування методів CompleteAdding(), Trytake і властивості IsCompleted. using System;
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Concurrent;
class BlockingDemo {
static BlockingCollection<char> be;
// Зробити й поставити символи від А до Z. static void Producer () {
for(char ch = 'A'; ch <= 'Z'; ch++) { be.Add(ch);
Console.WriteLine("Виробляється символ " + ch);
)
be.CompleteAdding();
)
// Споживати символи доти, поки їх буде робити постачальник.
static void Consumer() { char ch;
while(!be.IsCompleted) { if(be.TryTake(out ch))
Console.WriteLine("Споживається символ " + ch);
}
I
static void Main() {
II Використати колекцію, що блокує, обмежену 4 елементами, be = new BlockingCollection<char>(4);
// Створити завдання постачальника й споживача.
Task Prod = new Task(Producer);
Task Con = new Task(Consumer);
// Запустити завдання.
Con.Start();
Prod.Start();
// Очікувати завершення обох завдань, try {
Task.WaitAll(Con, Prod);
} catch(AggregateException exc) (
Console.WriteLine (exc);
) finally {
Con.Dispose();
Prod.Dispose(); be.Dispose();
)
}
Цей варіант програми дає такий же результат, як і попередній. Головна його відмінність полягає в тім, що тепер метод Producer () може робити й поставляти скільки завгодно елементів. Із цією метою він просто викликає метод CompleteAdding (), коли завершує створення елементів. А метод Consumer () лише "споживає" зроблені елементи доти, поки властивість IsCompleted не прийме логічне значення true.
Незважаючи на специфічний певною мірою характер паралельних колекцій, призначених в основному для паралельного програмування, у них, проте, є чимало загального зі звичайними, непаралельними колекціями, описаними в попередніх розділах. Якщо ж вам доводиться працювати в середовищі паралельного програмування, то для організації одночасного доступу до даних з декількох потоків вам, швидше за все, прийде скористатися паралельними колекціями.
Сохорона об'єктів, обумовлених користувачем класів, у колекції.
Заради простоти наведених вище прикладів у колекції, як правило, зберігалися об'єкти убудованих типів, у тому числі int, string i char. Але адже в колекції можна зберігати не тільки об'єкти убудованих типів. Достоїнство колекцій у тім і складається, що в них допускається зберігати об'єкти будь-якого типу, включаючи об'єкти обумовлених користувачем класів.
Розглянемо спочатку простий приклад застосування класу неузагальненої колекції ArrayList для зберігання інформації про товарні запаси. У цьому класі инкапсулируется клас Inventory.
// Простий приклад колекції товарних запасів.
using System;
using System.Collections;
class Inventory { string name; double cost; int onhand;
public Inventory(string n, double c, int h) { name = n; cost = c; onhand = h;
)
public override string ToString { return
String.Format("{0,-10)Вартість: {1,6:З) Наявність: {2}", name, cost, onhand);
}
class InventoryList { static void Main() {
ArrayList inv = new ArrayList();
// Додати елементи в список. inv.Add(new Inventory("Гострозубці", 5.95, 3)); inv.Add(new Inventory("Викрутки", 8.29, 2)); inv.Add(new Inventory("Молотки", 3.50, 4)); inv.Add(new Inventory("Дриля", 19.88, 8));
Console.WriteLine("Перелік товарних запасів:"); foreach(Inventory i in inv) {
Console.WriteLine (" " + i);
При виконанні програми з даного приклада виходить наступний результат.
Перелік товарних запасів:
Гострозубці Вартість: $5.95 Наявність: 3
Викрутки, Вартість: $8.29 Наявність: 2
Молотки Вартість: $3.50 Наявність: 4
Дриля Вартість: $19.88 Наявність: 8
Зверніть увагу на те, що в даному прикладі програми не треба було ніяких спеціальних дій для збереження в колекції об'єктів типу Inventory. Завдяки тому що всі типи успадковують від класу object, у неузагальненій колекції можна зберігати об'єкти будь-якого типу. Саме тому в неузагальненій колекції неважко зберегти об'єкти обумовлених користувачем класів. Безумовно, це також означає, що така колекція не типізована.
Для того щоб зберегти об'єкти обумовлених користувачем класів у типізованій колекції, прийде скористатися класами узагальнених колекцій. Як приклад нижче наведений змінений варіант програми з попереднього приклада. У цьому варіанті використається клас узагальненої колекції List<T>, а результат виходить таким же, як і колись.
// Приклад збереження об'єктів класу Inventory в // узагальненій колекції класу List<T>.
using System;
using System.Collections.Generic;
class Inventory { string name; double cost; int onhand;
public Inventory(string n, double c, int h) { name = n; cost = c; onhand = h;
public override string ToString { return
String.Format ("{0,-10}Вартість: {1,6:З} Наявність: (2)", name, cost, onhand);
)
class TypeSafelnventoryList { static void Main() (
List<Inventory> inv = new List<Inventory>();
// Додати елементи в список. inv.Add(new Inventory("Гострозубці", 5.95, 3)); inv.Add(new Inventory("Викрутки", 8.29, 2)); inv.Add(new Inventory("Молотки", 3.50, 4)); inv.Add(new Inventory("Дриля", 19.88, 8));Console.WriteLine("Перелік товарних запасів:"); foreach(Inventory i in inv) (
Console.WriteLine(" " + i);
I
}
Даний приклад відрізняється1 від попередньою лише передачею типу Inventory як аргумент типу конструкторові класу List<T>. А в іншому обидва приклади розглянутої тут програми практично однакові. Це, власне кажучи, означає, що для застосування узагальненої колекції не потрібно ніяких особливих зусиль, але при збереженні в такій колекції об'єкта конкретного типу строго дотримується типова безпека.
Проте для обох прикладів розглянутої тут програми характерна ще одна особливість: вони досить короткі. Якщо врахувати, що для організації динамічного масиву, де можна зберігати, витягати й обробляти дані товарних запасів, буде потрібно не менш 40 рядків коду, то переваги колекцій відразу ж стають очевидними. Неважко догадатися, що розглянута тут програма вийде длиннее в кілька разів, якщо спробувати закодувати всі ці функції колекції вручну. Колекції пропонують готові рішення самих різних завдань програмування, і тому їх варто використати при всякому зручному випадку.
У розглянутої тут програми є все-таки один не зовсім очевидний недолік: колекція не підлягає сортуванню. Справа в тому, що в класах ArrayList i List<T> відсутні засобу для порівняння двох об'єктів типу Inventory. Але із цього положення є два виходи. По-перше, у класі Inventory можна реалізувати інтерфейс IComparable, у якому визначається метод порівняння об'єктів даного класу. І по-друге, для цілей порівняння можна вказати об'єкт типу IComparer. Обидва підходи розглядаються далі по черзі.
Реалізація інтерфейсу IComparable
Якщо потрібно відсортувати колекцію, що складається з об'єктів обумовленого користувачем класу, за умови, що вони не зберігаються в колекції класу SortedList, де елементи розташовуються у відсортованому порядку, то в такій колекції повинен бути відомий спосіб сортування об'єктів, що втримуються в ній. Із цією метою можна, зокрема, реалізувати інтерфейс IComparable для об'єктів типу, що зберігає. Інтерфейс IComparable доступний у двох формах: узагальненої й неузагальненої. Незважаючи на подібність застосування обох форм даного інтерфейсу, між ними є деякі, хоча й невеликі, відмінності, розглянуті нижче.
Реалізація інтерфейсу IComparable для неузагальнених колекцій
Якщо потрібно відсортувати об'єкти, що зберігаються в неузагальненій колекції, то для цієї мети прийде реалізувати неузагальнений варіант інтерфейсу IComparable. У цьому варіанті даного інтерфейсу визначається тільки один метод, CompareTo ПРО, що визначає порядок виконання самого порівняння. Нижче наведена загальна форма оголошення методу CompareTo ().
