OOP Course
Сьогодні

Підрозділ 7.5

Інтерфейси в узагальненнях

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

7.5. Інтерфейси в узагальненнях

Інтерфейси та узагальнення (generics) тісно взаємодіють між собою у C#. З одного боку, інтерфейси виступають як обмеження (constraints) для узагальнених типів — вони гарантують, що параметр типу T реалізує певний контракт. З іншого боку, самі інтерфейси можуть бути узагальненими — тобто мати власний параметр типу T, яким їхні члени типізуються під час реалізації.

Інтерфейси як обмеження узагальнень

Коли ви оголошуєте узагальнений клас або метод, ви можете обмежити допустимі типи для параметра T за допомогою ключового слова where. Інтерфейс у ролі обмеження означає: «T повинен реалізовувати цей інтерфейс». Компілятор перевіряє це під час збірки — і якщо спробувати підставити тип, що не відповідає обмеженню, виникне помилка до запуску програми.

Ключова перевага перед обмеженнями за класом: обмежень-інтерфейсів можна вказати скільки завгодно, тоді як базовий клас у where може бути лише один.

// можна вказати кілька інтерфейсів:
class ClinicReporter<T> where T : IExaminable, IPrintable { }

// але базовий клас — тільки один (і він йде першим):
class ClinicReporter<T> where T : BaseMedical, IExaminable, IPrintable { }

Розглянемо практичний приклад. У клінічній системі є два інтерфейси: IExaminable описує об'єкти, щодо яких можна провести огляд, а IPrintable — об'єкти, що підтримують виведення звіту. Клас ClinicReporter<T> приймає лише ті типи, що реалізують обидва:

Обмеження узагальнень

Зверніть увагу: ClinicReporter<Nurse> не скомпілюється взагалі — компілятор повідомить про порушення обмеження ще на етапі збірки. Це набагато безпечніше, ніж перевірка типу під час виконання.

Інтерфейс як параметр типу

Обмеження where T : IExaminable, IPrintable задовольняє не лише клас, а й інтерфейс, що успадковує обидва. Наприклад:

Узагальнені інтерфейси

Інтерфейси, як і класи, можуть бути узагальненими — тобто мати власний параметр типу T. Це дозволяє визначати гнучкі контракти, де конкретні типи підставляються під час реалізації.

Типовий приклад: інтерфейс сутності зі значенням ідентифікатора, тип якого може варіюватися:

interface IEntity<TId>
{
    TId Id { get; }
}

Клас Patient може використовувати int як тип ідентифікатора, а InsurancePolicy — рядок (GUID або номер поліса):

Фіксований параметр типу

Під час реалізації узагальненого інтерфейсу клас може відразу зафіксувати конкретний тип замість T, не стаючи сам узагальненим:

Фіксація типу корисна, коли клас точно знає, який тип ідентифікатора він використовує, і не потребує гнучкості: лікарі завжди мають числовий id, а ліцензії — рядковий номер.

Підсумок

Інтерфейси та узагальнення взаємодіють у двох напрямах:

  • Інтерфейс як обмеження (where T : IExaminable, IPrintable) — гарантує, що тип T реалізує необхідний контракт. Допускається декілька інтерфейсів одночасно. Компілятор перевіряє обмеження під час збірки.
  • Узагальнений інтерфейс (IEntity<TId>) — дозволяє параметризувати контракт типом. Клас реалізує інтерфейс або підставляючи конкретний тип, або залишаючись узагальненим сам.
Розроблено Tomka Yurii · © 2026 ·