Підрозділ 8.3
Перевантаження операцій перетворення типів
Показує перевантаження явних і неявних перетворень типів між примітивними та власними складними типами.
8.3. Перевантаження операцій перетворення типів
У розділі 2 ми розглядали неявні та явні перетворення між примітивними типами: int → long відбувається автоматично (implicit), а double → int потребує явного cast-у (explicit). Той самий механізм можна визначити і для власних класів — це перевантаження операторів перетворення типів.
Завдяки цьому ми можемо навчити компілятор, як перетворювати об'єкт нашого типу на інший тип (і навпаки), і контролювати — чи це відбуватиметься автоматично, чи лише при явному приведенні. Наприклад, у клінічній системі зручно присвоювати числове значення температури безпосередньо об'єкту BodyTemperature:
BodyTemperature t = 36.6; // implicit: double → BodyTemperature
double c = (double)t; // explicit: BodyTemperature → doubleСинтаксис оператора перетворення
Оператор перетворення визначається як статичний метод у класі або структурі:
public static implicit|explicit operator ТипРезультату(ВхіднийТип param)
{
// логіка перетворення
}public static— обов'язкові модифікатори.implicitабоexplicit— визначає, чи потрібен явний cast.operator— ключове слово.ТипРезультату— тип, до якого перетворюємо.ВхіднийТип param— тип і параметр, з якого перетворюємо.

Обмеження: оператор перетворення повинен або приймати параметром об'єкт свого типу, або повертати об'єкт свого типу. Тобто оператор визначений у класі BodyTemperature може перетворювати double → BodyTemperature (повертає свій тип) або BodyTemperature → double (приймає свій тип). Визначити оператор між двома чужими типами в середині третього класу — неможливо.
implicit: неявне перетворення
Неявне перетворення відбувається автоматично — без жодного синтаксису з боку програміста. Використовується тоді, коли перетворення безпечне, без втрати даних і семантично очевидне.
Визначимо implicit-перетворення з double у BodyTemperature — створення температури з числового значення:
Завдяки implicit ми можемо писати BodyTemperature t = 36.6 — компілятор сам викличе оператор перетворення. Це зручно і читабельно, адже семантика очевидна: число 36.6 — це температура в градусах Цельсія.
explicit: явне перетворення
Явне перетворення вимагає від програміста написати cast явно: (ТипРезультату). Це сигнал: «я свідомо роблю це перетворення і розумію наслідки».
Визначимо explicit-перетворення з BodyTemperature у double — вилучення числового значення температури:
Чому тут explicit, а не implicit? Коли ми витягуємо double з BodyTemperature, результат втрачає семантичний контекст — це вже «просто число», а не температура. Програміст має явно підтвердити, що він хоче саме це. Якщо б перетворення було неявним, можна було б випадково отримати число там, де очікувався об'єкт BodyTemperature, і не помітити помилки.
Перетворення між двома власними типами
Оператори перетворення можна визначити і між двома складовими типами. Розглянемо конвертацію між BodyTemperature (градуси Цельсія) і FahrenheitTemperature (градуси Фаренгейта) — типова задача в міжнародних клінічних системах:
Обидва перетворення тут explicit, бо вони нетривіальні: задіяна формула, є заокруглення, і читач коду повинен бачити, що відбувається перетворення між системами вимірювання. Неявне перетворення тут приховало б важливий факт.
Коли обирати implicit, а коли explicit
| Критерій | implicit | explicit |
|---|---|---|
| Можлива втрата даних? | Ні | Так (або невідомо) |
| Семантика очевидна? | Так | Неочевидна або потребує уваги |
| Задіяна нетривіальна формула? | Ні | Так |
| Перетворення між різними одиницями вимірювання? | Ні | Так |
| Приклад у клінічному домені | double → BodyTemperature |
BodyTemperature → FahrenheitTemperature |
Загальне правило: якщо є хоч найменший сумнів — робіть explicit. Явний cast у коді — це документація: він повідомляє читачеві, що тут відбувається свідоме перетворення типів.