Управління колекціями до С # 2.0

До С # 20 основні класи колекцій перебували в просторі імен SystemCollections Далі наводиться список деяких класів та інтерфейсів даного простору імен

• ArrayList – загальна колекція, що управляє всіма обєктами, на які є посилання, за допомогою внутрішнього масиву Даний клас вирішує прлему із збільшенням розміру масиву

П HashTabie – колекція, в якій окремі обєкти зберігаються у вигляді пар ключ / значення. У попередньому розділі для отримання кімнатної угруповання за її ідентифікатором застосовувався індексатор Те ж саме можна було б зробити за допомогою Ю Колекції HashTabie

• icollection-інтерфейс, реалізований класом ArrayList і надає базову функціональність, яка копіює всі елементи в інший масив

• iDictionary-інтерфейс, реалізований класом HashTabie і що дозволяє асоціювати ключ зі значенням

• iList – інтерфейс, реалізований класом ArrayList і надає мехізм загального доступу для маніпулювання колекцією елементів

• Queue – колекція, що реалізує механізм FIFO (First In – First out, першим прийшов – першим обслужений, черга) Даний клас можна використовувати для обробки набору інструкцій Інструкція, яку необхідно обробити першого, буде додана в колекцію перших

• stac k – колекція, що реалізує механізм LIFO (Last In – Last Out, послеім прийшов – першим обслужений, стек) Даний клас можна розглядати як стопку аркушів паперу, з якої першим знімається лист, покладений в неї останнім

Всі ТИПИ колекцій – ArrayList, HashTabie, Queue І Stack-реалізують спосіб для зберігання набору типів Різниця між цими типами колекцій полягає в тому, яким чином окремі обєкти зберігаються і витягуються з колекції Приклади використання різних типів колекцій наводяться врозд Дополнельние відомості про типи колекцій далі в цьому розділі

Простий приклад колекції

Розглянемо крок за кроком приклад використання колекції в стилі до С # 20 Соайте нове консольного додаток назвіть його oneToManySampies Потім додайте до проекту новий клас Для цього клацніть правою кнопкою миші

за назвою проекту в Solution Explorer і виберіть команду меню Add | Class | Class Надайте йому імя Examplecs і вставте в нього наступний код:

using SystemCollections

class Example { int _value

public int Value { get {

return _value

}

set {

_value = value

}

}

}

static class Tests {

static void PlainVanillaObjects() {

IList objects = new ArrayList()

objectsAdd(new Example { Value =1 0 }) objectsAdd(new Example { Value = 20 })

foreach (Example obj in objects) { ConsoleWriteLine(&quotObject value (&quot + objValue + &quot)&quot)

}

}

public static void RunAllO { PlainVanillaObjects()

}

}

Це тип коду, застосовуваний до версії С # 20 при його написанні виконується стаартная послідовність кроків:

1 Визначається користувача тип У даному прикладі назва типу – Example

2 Створюються і додаються в колекцію екземпляри користувальницького типу

У прикладі в колекцію типу ArrayList додаються два примірники класу

Example

3 Виконується маніпулювання колекцією, щоб отримати доступ для роботи з користувацькими типами У прикладі колекція ArrayList є екземяром інтерфейсу IList

Жирним шрифтом в прикладі виділений код, що виконує основні дії Соан примірника типу Array реалізується адміністратор колекції Після цього примірник ArrayList присвоюється змінним обєктів типу iList Інтерфейс iList дозволяє використовувати колекцію в контексті компонентно-орієнтованого середовища розробки Щоб додати до колекції два обєкти, двічі викликається метод Add () Для проходження в циклі за елементами колекції застосовується опатор foreach

ПРИМІТКА

Та обставина, що класи колекції можна використовувати в контексті компонує-орієнтованого додатки, не є випадковістю Коли в Microsoft створили бібліотеку NET, компонентам в ній відводилася одна з головних ролей

Щоб виконати тести, відкоригуйте файл Programes наступним чином:

class Program

{

static void Main(string] args)

{

TestsRunAll()

}

}

Для запуску програми натисніть комбінацію клавіш +

Проблема зі змішаними типами

У коді прикладу унікальним є те, що оператор foreach справді раба належним чином і знає, що обєкти в колекції належать до типу Example Але наступний код вставляє в колекцію обєкт, який викличе збій у роботі циклу:

class Another { }

IList objects = new ArrayListO objectsAdd(new Example { Value = 10 }} objectsAdd(new Example { Value =2 0 }) objectsAdd(new Another())

foreach (Example obj in objects) { ConsoleWriteLine(&quotObject value (&quot + objValue + &quot)&quot)

}

Жирним шрифтом виділено код, який ілюструє, що обєкт колекції соді два примірники типу Example та один примірник типу Another Даний код скомпіліруется без помилок, таким чином, вводячи нас в оману, що з ним

все в порядку Але при спробі виконати додаток (у звичайному або отладочном режимі) буде виведено наступне повідомлення:

Unable to cast object of type Another to type Example.1

Що ж тепер, застосовувати в колекції кілька типів Аргументи є за і проти такого рішення, але проблема не полягає в можливості змішування типів, а в тому, що їх можна змішувати, навіть коли це не входить в наміри розробника

Використання ключового слова foreach зі змішаними типами викличе іскленіе, т к в кожній ітерації обєкт колекції приводиться до типу Example Так як останній елемент колекції має тип Another, приведення буде неуспеим, що і викликає виняток До NET 20 в колекціях не можна було прінуать несуперечливість типів, і це було проблемою

Для змішаних типів правильним циклом foreach був би наступний:

foreach (object obj in objects) { if (obj is Example) {

//  ..

}

else if (obj is Another) {

I I

}

}

Проблема із звичайними типами

Іншою проблемою з колекціям в більш ранніх версіях С #, ніж версія 20, явлтся низька продуктивність Для прикладу розглянемо наступний код, котий маніпулює звичайними типами:

IList objects = new ArrayListO objectsAdd(l)

objectsAdd(2)

foreach (int val in objects) { ConsoleWriteLine(&quotValue (&quot + val + &quot)&quot)

}

У прикладі знову створюється екземпляр ArrayList, але на цей раз в колекцію давлять числа 1 і 2 Потім ці числа обробляються в циклі foreach Хоча цей код і працює, в ньому є не відразу видимий аспект, негативно впливає на продуктивність У колекцію додаються значення звичайного типу, що означає маніпулювання памяттю стека

Але визначення IList використовує обєкти:

public interface IList : ICollection, IEnumerable

{

1 Неможливо привести обєкт типу Another до типу Example

/ / Методи

int Add(object value) void Clear()

bool Contains(object value) int IndexOf(object value)

void Insert(int index, object value) void Remove(object value)

void RemoveAt(int index)

/ / Властивості

bool IsFixedSize { get } bool IsReadOnly { get }

object this[int index] { get set }

}

Спосіб визначення iLis t і звичайного типу повинен насторожувати Так як обєкт є посилальним типом, у нас є конфлікт: в iLis t зберігаються посилальні типи, але in t є звичайним типом

Тут середу NET знає про конфлікт і виправляє його Не слід розглядати це виправлення як рішення на швидку руку для даної проблеми, а як Дейсі, в якому беруть участь всі середовища віртуальних машин, подібних NET У середовищі NET для вираження перетворення посилального типу в звичайний і звертаючись застосовуються терміни Упаковка (Boxing) і Розпакування (Unboxing) соответвенно

Для полегшення розуміння ідей упаковки і розпаковування розглянемо приклад Дуст, що ви створюєте список, який звертається до звичайних типам Масив являея посилальним типом, що зберігається в купі, в той час як звичайні типи зберігаються в стеку Якщо масив буде звертатися до даних в стеку, то це викличе проблему сумісності типів Таким чином, нам необхідно перемістити память зі ста в купу, але це б порушило принцип, лежить в основі звичайних типів Решіем є компроміс у вигляді упаковки і розпаковування

Щоб проілюструвати, що відбувається при упаковці, я написав код, працюють подібні операції упаковки звичайного типу Різниця полягає в тому, що в коді операція виконується явно, а при упаковці – неявно

class ReferenceHeap { public int Value

}

public static void MethodO { int onStack = 1

ReferenceHeap onHeap = new ReferenceHeap {Value = onStack}

}

У даному прикладі в методі Method *) оголошується змінна onstack звичайного типу, память для якого виділяється в контексті методу, тобто в стек Тип ReferenceHeap є класом і тому посилальним типом відповідно, всі його дані автоматично зберігаються в купі Коли оголошується і ініціалізіртся мінлива опнеар, значення змінної onstack переміщається в купу і присвоюється екземпляру опнеар Те ж саме відбувається і при виконанні операції упаковки, але тільки автоматично і прозоро для користувача При роботі зі списками у версіях, що передують С # 20, всі звичайні типи автоміческі упаковуються і розпаковуються

ПРИМІТКА

Важливо памятати, що при виконанні упаковки і розпаковування переміщуються значення Тому, при зміні значення змінної onstack, значення змінної опнеар не зміниться

При розпакуванні значення переміщається з купи в стек, що у випадку з нашим Прима означає переміщення значення з змінної опнеар в змінну onstack

Упаковка та розпакування виконуються автоматично, але за це доводиться расплачаться пониженням продуктивності, т к виконуються операції виділення пяти і присвоювання значень

Джерело: Гросс К С # 2008: Пер з англ – СПб: БХВ-Петербург, 2009 – 576 е: ил – (Самовчитель)

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*