Підрозділ 8.7
Часткові класи та методи
Пояснює часткові класи й методи, рознесення одного класу між кількома файлами та обмеження partial-методів.
8.7. Часткові класи та методи
Зазвичай клас визначається в одному файлі. Але бувають ситуації, коли один і той самий клас зручно або необхідно розподілити між кількома файлами. Саме для цього у C# існує механізм часткових класів (partial classes) — можливість визначати один тип у декількох місцях, а компілятор під час збірки об'єднає всі частини в єдине ціле.
Навіщо потрібні часткові класи
Найважливіший практичний сценарій — генератори коду. Коли середовище розробки або фреймворк автоматично генерує частину класу (наприклад, WinForms-дизайнер генерує ініціалізацію UI-компонентів, а Entity Framework — опис таблиць бази даних), зручно тримати цей згенерований код окремо від коду, написаного вручну. При кожному оновленні інструмент перегенеровує «свій» файл, не торкаючись «вашого». Без partial це було б неможливо без постійних конфліктів злиття.
Другий сценарій — великі класи, в яких логічно виділити окремі «зони відповідальності»: базові властивості, медична інформація, допоміжні методи. Замість одного файлу на 2000 рядків ми розбиваємо клас на кілька файлів — кожен відповідає за свою ділянку. При цьому з точки зору мови це все ще один тип.
Третій сценарій — розподіл роботи в команді: різні розробники можуть паралельно додавати функціональність до одного класу у різних файлах, не отримуючи конфліктів.
Синтаксис і механізм компіляції
Для визначення часткового класу перед ключовим словом class (або struct, interface, record) додається модифікатор partial:
public partial class Patient { ... } // у першому файлі
public partial class Patient { ... } // у другому файліСлово partial — це виключно директива для компілятора, а не частина метаданих типу. У скомпільованому IL-коді існує один-єдиний тип Patient з усіма членами з усіх частин. Жодного накладу у виконанні немає.

Правила сумісності часткових визначень. Всі частини одного partial типу повинні:
- Перебувати в одному просторі імен (
namespace). - Перебувати в одному assembly (проєкті).
- Мати однакове ім'я і однакові загальні модифікатори доступу (
public,internalтощо). - Якщо тип успадковує інший — базовий клас можна вказати лише в одному
partial-визначенні, або в усіх, але однаково.
Якщо одна частина оголошує partial class Patient : Person, а інша просто partial class Patient — це допустимо. Але якщо дві частини вказують різні базові класи — помилка компіляції.
Що може бути partial
Модифікатор partial можна застосувати до:
| Тип | Синтаксис |
|---|---|
| Клас | public partial class Patient { } |
| Структура | public partial struct BloodPressure { } |
| Інтерфейс | public partial interface IPatientRecord { } |
| Record (C# 9+) | public partial record Patient(string Name, int Age); |
Вкладені типи також можуть бути partial. Але методи, поля, властивості — ні; partial застосовується тільки до типів (і до окремої категорії часткових методів, про яку йдеться далі).
Клінічний приклад: розподіл класу Patient
У реальному проєкті ці два partial блоки знаходились би у різних файлах. У runnable-прикладі вони в одному файлі — C# це допускає, оскільки partial є лише підказкою компілятору про дозвіл на розподіл, а не вимогою.
Часткові методи
Часткові класи можуть містити часткові методи (partial methods). Ідея полягає в тому, що одна частина класу оголошує сигнатуру методу (без тіла), а інша — надає реалізацію. Це корисно саме в контексті code generation: генератор може оголосити «точки розширення», а розробник заповнює їх реалізацією.
// Частина 1 (згенерована автоматично):
public partial class Patient
{
partial void OnDiagnosisChanged(string newDiagnosis); // тільки оголошення
public void SetDiagnosis(string diagnosis)
{
Diagnosis = diagnosis;
OnDiagnosisChanged(diagnosis); // викликаємо — можливо порожній виклик
}
}
// Частина 2 (написана вручну розробником):
public partial class Patient
{
partial void OnDiagnosisChanged(string newDiagnosis)
{
Console.WriteLine($"Діагноз змінено: {newDiagnosis}");
// тут можна надіслати сповіщення, зробити логування тощо
}
}Ключова особливість: якщо реалізація часткового методу відсутня, компілятор просто видаляє виклик OnDiagnosisChanged(diagnosis) з коду. Жодної помилки компіляції, жодних витрат на виконання — виклик зникає повністю. Це фундаментально відрізняє часткові методи від абстрактних: абстрактний метод без реалізації — помилка компіляції; частковий — тиха відмова.
Обмеження базових часткових методів
У базовій формі часткові методи мають низку обмежень. Всі вони пов'язані з однією причиною: компілятор повинен мати можливість безслідно видалити виклик, якщо реалізація відсутня.
| Обмеження | Причина |
|---|---|
Немає модифікатора доступу (за замовчуванням private) |
public метод без реалізації — порушення контракту типу |
Тип результату — лише void |
Не можна видалити виклик, якщо код очікує повернуте значення |
Немає out-параметрів |
Невизначені out після видаленого виклику — помилка |
Немає virtual, override, sealed, new, extern |
Ці модифікатори вимагають реальної реалізації у типі |
Розширені часткові методи (C# 9+)
Починаючи з C# 9, часткові методи можуть мати будь-які модифікатори доступу та будь-який тип результату — за однієї умови: реалізація обов'язкова. Такий варіант не може бути «тихо видалений», тому компілятор вимагає наявності тіла.
// Оголошення з public і non-void:
public partial class PatientRecord
{
public partial string GenerateSummary(); // C# 9 — реалізація обов'язкова
}
// Реалізація — ОБОВ'ЯЗКОВО в іншій частині:
public partial class PatientRecord
{
public partial string GenerateSummary()
=> $"Пацієнт: {Name}, вік: {Age}, діагноз: {Diagnosis}";
}Розширені часткові методи корисні у Source Generators (C# 10+), де генератор оголошує метод-«заглушку», а розробник надає конкретну реалізацію, яка може повертати значення і бути публічною.
Підсумок: базові vs розширені часткові методи
| Характеристика | Базовий partial (C# 3) |
Розширений partial (C# 9) |
|---|---|---|
| Модифікатор доступу | Тільки private (implicit) |
Будь-який |
| Тип результату | Тільки void |
Будь-який |
out-параметри |
Заборонені | Дозволені |
| Реалізація | Необов'язкова | Обов'язкова |
| Без реалізації | Виклик видаляється | Помилка компіляції |