Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
c#_theoretical_1.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
1.07 Mб
Скачать

Тема 4 Узагальнення Поняття узагальнених класів

Термін узагальнення, по суті, означає параметризований тип. Особлива роль параметризованих типів полягає в тому, що вони дозволяють створювати класи, структури, інтерфейси, методи та деякі інші члени класу, у яких тип оброблюваних даних вказується у вигляді параметра. За допомогою узагальнень можна, наприклад, створити єдиний клас, який автоматично стає придатним для обробки різнотипних даних. Клас, структура, інтерфейс або метод, що оперує параметризованим типом даних, називається узагальненим, як, наприклад, узагальнений клас або узагальнений метод.

Слід відмітити, що у С# є можливість створювати узагальнений код, оперуючи посиланнями типу object. Як вам уже відомо клас object є базовим для всіх інших класів, а отже, за посиланням на тип object можна звертатися до об’єкта будь-якого типу. Недоліком такого підходу є недотримання типової безпеки (безпеки типів). Для перетворення типу object у конкретний тип даних необхідне приведення типів, яке може бути джерелом помилок. Застосування узагальнень, навпаки, забезпечує типову безпеку і тим самим не вимагає виконання приведення типів для перетворення об’єкта або іншого типу оброблюваних даних. Таким чином, узагальнення розширюють можливості повторного використання коду та дозволяють робити це надійно та просто.

Нижче наведена загальна форма оголошення узагальненого класу.

class ім'я_класу <список_параметрів_типу>

{

// ...

}

А от як виглядає синтаксис оголошення посилання на узагальнений клас.

ім’я_класу <список_аргументів_типу> ім’я_змінної =

new ім’я_класу<список_ аргументів_типу> (список_аргументів_конструктора);

Розглянемо можливості та переваги використання узагальнень на прикладі розробки класу «Множина». Нагадаємо, що у математиці у рамках наївної теорії множин Г. Кантора поняття множини відноситься до одного із аксіоматичних понять (такого, що не має визначення), і, як правило, під множиною розуміють сукупність всіх об’єктів, які володіють певною визначеною властивістю.

// узагальнений клас «Множина»

class Set<T>

{

}

У наведеному прикладі при визначенні класу Set використано один параметризований тип (параметр типу), що має ідентифікатор Т – ім’я загального типу. Це ім’я вказує місце підстановки конкретного типу, який вказується при створенні об’єкта класу Set. Отже, ім’я Т використовується в класі Set кожного разу, коли потрібен параметр типу. Тут слід відмітити також, що із загального правила оголошення узагальнених класів випливає, що узагальнений клас може бути побудований на декількох узагальнених типах. Тоді їх імена вказуються у дужках «< >» через кому.

Ім’я Т може використовуватися при оголошенні членів узагальненого класу. Наприклад у нашому випадку використаємо його при оголошенні масиву elements для збереження елементів множини.

class Set<T>

{

T[] elements; // масив елементів множини, елементи мають загальний тип Т

}

Оскільки ім’я параметру типу Т вказує на місце підстановки конкретного типу при створенні об’єкту класу Set, тому масив elements буде мати тип, що прив’язується до Т при створенні об’єкта класу Set. Так, якщо замість Т вказується тип double, то в екземплярі даного класу елементи масиву elements будуть мати тип double. Типи, що підставляються, називаються аргументами типу.

Параметр типу також може використовуватися при оголошенні параметрів методів узагальненого класу. Наприклад як у випадку наступної реалізації конструктору класу Set.

class Set<T>

{

...

// конструктор класу з параметрами

public Set(params T[] arg)

{

if (arg.Length == 0)

elements = null;

else

{

// копіювання масиву елементів множини

elements = new T[arg.Length];

arg.CopyTo(elements, 0);

}

}

}

Параметр arg та масив elements належать до одного і того самого узагальненого типу Т. Конкретний тип обох масивів визначиться в момент створення об’єкта класу Set.

За допомогою параметра типу Т можна також указувати тип, що повертається методом. Наприклад.

class Set<T>

{

...

// індексатор доступу до елементів множини за номером

public T this[int index]

{

set

{

if (index < 0 || index >= elements.Length)

throw new Exception("Iндекс елемента виходить за межi множини!");

elements[index] = value;

}

get

{

if (elements.Length == 0)

throw new Exception("Множина порожня!");

if (index < 0 || index >= elements.Length)

throw new Exception("Iндекс елемента виходить за межi множини!");

return elements[index];

}

}

}

Елементи масиву elements відносяться до типу Т, тому їх тип співпадає із типом, що повертається індексатором this[int].

Нижче наводиться приклади використання узагальненого класу Set.

// приклад створення об'єкта-множини для цiлих чисел

Set<int> s1 = new Set<int>(1,2,3,4,5);

// приклад створення об'єкта-множини для дiйсних чисел

Set<double> s2 = new Set<double>(1.0, 2.0, 3.0, 4.0, 5.0);

// приклад створення об'єкта-множини для раціональних чисел

Set<Rational> s3 = new Set<Rational>(new Rational(1,2), new Rational(3,4), new Rational(5,1));

У цьому методі створюються три множини: для зберігання цілих чисел, дійсних чисел та раціональних чисел. Ім’я конкретного типу даних елементів множини вказується замість параметру типу T у дужках «< >» при створенні екземпляра класу Set. У кожному екземплярі параметр типу T замінюється конкретним типом всюди, де він зустрічається (у методах, у властивостях, в оголошенні полів класу і т.д.).

Відмітимо, що два екземпляри класу Set для різних аргументів типів елементів, наприклад, для int та для double, навіть якщо ці типи сумісні належать до різних типів даних і тому не можуть бути приведеними одне до одного. Наступний код містить помилку, тому що в ньому робиться спроба привласнити посиланню на тип Set<int> посилання на об’єкт типу Set<double>.

Set<double> s = new Set<int>(1,2,3,4,5); // Помилка

Тип, утворений внаслідок підстановки аргументів типу, називається сконструйованим типом. У якості аргументу типу може бути підставлений як конкретний тип (наприклад int, double, Rational або string), так і сконструйований тип. У першому випадку сконструйований тип є так званим закритим типом або спеціалізацією (конструюється спеціалізована версія узагальненого типу), а в другому − відкритим. Так у наведеному вище прикладі Set<int> є сконструйованим закритим типом. Процес створення сконструйованого типу з узагальненого типу називається generic type instantiation.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]