
- •Тема 1 Програмна технологія Microsoft .Net. Вступ
- •Загальна характеристика платформи .Net Framework
- •Єдине середовище виконання clr
- •Єдина система типів cts
- •Бібліотека базових типів bcl
- •Розбір найпростішої програми на мові с
- •Загальна структура програми на мові c#
- •Створення .Net-додатків з використанням csc.Exe
- •Створення .Net-додатків на мові c# з використанням ide Visual с# 2010 Express
- •Тема 2 Класи в c# Вступ
- •Синтаксис опису класу
- •Поля класу
- •Методи класу
- •Властивості та індексатори
- •Конструктори
- •Деструктор
- •Перевантаження операцій
- •Частинні випадки класу
- •Структура «Раціональне число»
- •Тема 3 Основні засоби розробки класів у c# Вступ
- •Успадкування
- •Поліморфне успадкування
- •Агрегація та композиція
- •Абстрактні класи
- •Інтерфейси
- •Тема 4 Узагальнення Поняття узагальнених класів
- •Обмеження (constraints) для параметрів типу
- •Узагальнені методи
- •Узагальнені інтерфейси
- •Недолік обмеження операцій
Обмеження (constraints) для параметрів типу
При визначенні узагальненого класу передбачається, що узагальнений тип може бути будь-яким, тобто компілятор «не знає», які конкретні типи будуть використовуватися в якості параметрів узагальнення. Тому параметри типу «за замовчуванням» розглядаються як тип object. Таким чином, при звертанні до параметризованого типу в узагальненні програміст може використовувати тільки методи, успадковані від класу object (Equals(), GetType(), ToString() та ін.). Це сильно обмежує вибір алгоритмів, які можуть використовуватися в методах узагальнення. Наприклад, нехай в узагальнення Set потрібно додати метод одержання мінімального елемента скінченної множини. Код даного методу міг би виглядати наступним чином:
// властивість для одержання мінімального елемента у множині public T Min { get { if (elements.Length == 0) throw new Exception("Множина порожня!"); T min = elements[0]; for (int i = 1; i < elements.Length; i++) if (elements[i] < min) // Помилка! min = elements[i]; return min; } } |
Помилка при компіляції цієї властивості викликана тим, що для класу object (а отже і для параметру типу T) не визначені операції порівняння об’єктів (у даному випадку, операція «<»).
Для виходу із подібних ситуацій у С# передбачено обмеження для параметрів типу: вказуючи параметр типу, можна накласти певне обмеження на цей параметр. Це робиться за допомогою оператора where при описанні параметра типу:
class ім'я_класу<параметр_типу> where параметр_типу : список_обмежень {...} |
де обмеження вказуються списком через кому.
У мові С# передбачено ряд обмежень на параметри типу.
Обмеження на узагальнення |
Призначення |
where параметр_типу : Ім’я_базового_класу |
Параметр типу має бути похідним від класу Ім’я_базового_класу. |
where параметр_типу : Ім’я_інтерфейсу |
Параметр типу повинен реалізовувати інтерфейс, зазначений як Ім’я_інтерфейсу. Можна задавати декілька інтерфейсів, розділяючи їх комами. Якщо обмеження накладається одночасно на базовий клас і інтерфейс, то першим у списку повинен бути зазначений базовий клас. |
where параметр_типу : struct |
Параметр типу повинен бути похідним від System.ValueType. Інакше кажучи, параметр типу повинен бути структурою. У цьому випадку, всяка спроба використовувати посилальний тип, наприклад string, замість параметру типу призведе до помилки під час компіляції. |
where параметр_типу : class |
Параметр типу не повинен бути похідним від System.ValueType, тобто належати до посилального типу. У цьому випадку, всяка спроба використовувати тип-значення, наприклад int або bool, замість параметру типу призведе до помилки під час компіляції. Слід пам’ятати, що, якщо є декілька обмежень на узагальнення, то обмеження class або struct повинно бути накладеним першим. |
where параметр_типу : new() |
Параметр типу повинен мати конструктор за замовчуванням. Це дуже корисно у випадку, якщо узагальнений тип повинен створювати екземпляри параметра типу. Слід пам’ятати, що в узагальненні із декількома обмеженнями це обмеження повинне вказуватися останнім. |
Приклади обмежень на параметри типу. Серед усіх цих обмежень найчастіше застосовуються обмеження на базовий клас та інтерфейс.
Обмеження на інтерфейс дозволяє вказувати інтерфейс, який повинен бути реалізований аргументом типу. Таке обмеження, по-перше, дозволяє використовувати члени інтерфейсу в узагальненому класі. І по-друге, воно гарантує використання тільки тих аргументів типу, які реалізують зазначений інтерфейс. Це означає, що для будь-якого обмеження, що накладається на інтерфейс, аргумент типу повинен позначати сам інтерфейс або ж тип, що реалізує цей інтерфейс.
Наприклад властивість одержання мінімального елемента у скінченній множині можна реалізувати для всіх типів, які реалізують інтерфейс IComparable, в якому визначений метод порівняння CompareTo(). Обмеження для узагальнення Set про те, що узагальнений тип повинен реалізовувати інтерфейс IComparable, записується так:
// узагальнений клас «Множина» із обмеженням на те, що елементи множини можна порівнювати class Set<T> where T: IComparable { ... // властивість для одержання мінімального елемента у множині public T Min { get { if (elements.Length == 0) throw new Exception("Множина порожня!"); T min = elements[0]; for (int i = 1; i < elements.Length; i++) if (elements[i].CompareTo(min)<0) min = elements[i]; return min; } } } |
Іноді важливо провести відмінність між посилальним типом та типом значення. Це можна зробити, використавши обмеження на посилальний тип або тип-значення. Наприклад, якщо наше узагальнення Set розробляється для роботи із різними множинами чисел (цілих, раціональних, дійсних, комплексних, тощо), то оскільки відповідним математичним поняттям, як правило, відповідають типи-значення, то у цьому випадку на Set доцільно накласти наступне обмеження.
class Set<T> where T: struct, IComparable { ... } |