Ответ
Чтобы полностью запретить наследование от класса, используется модификатор sealed.
Синтаксис:
public sealed class ApiResponse
{
public string Data { get; set; }
public int StatusCode { get; set; }
}
// Попытка наследования вызовет ошибку компиляции CS0509:
// 'DerivedResponse': cannot derive from sealed type 'ApiResponse'
public class DerivedResponse : ApiResponse { }
Зачем это нужно?
- Защита инвариантов и дизайна: Когда класс реализует специфичную логику, нарушаемую при наследовании (например, кэширование, синглтон, безопасность).
- Оптимизация производительности: Компилятор JIT может применять агрессивные оптимизации (девиртуализацию вызовов), зная, что метод не будет переопределен в производном классе.
- Контроль над иерархией: Явное указание, что класс является конечным в иерархии.
Частичное запрещение: Можно запретить переопределение отдельных методов в незапечатанном классе, используя sealed для метода.
public class PaymentProcessor
{
// Базовый виртуальный метод
public virtual void Validate() { /* общая логика */ }
}
public class CreditCardProcessor : PaymentProcessor
{
// Переопределяем и ЗАПЕЧАТЫВАЕМ метод.
// Дальнейшее переопределение в наследниках CreditCardProcessor будет невозможно.
public sealed override void Validate()
{
base.Validate();
// + специфичная проверка карты
}
}
public class PremiumCardProcessor : CreditCardProcessor
{
// Ошибка CS0239: нельзя переопределить запечатанный метод.
// public override void Validate() { }
} Ответ 18+ 🔞
Ну ты смотри, какой прикол! Вот есть у тебя класс, и ты такой: "Всё, ребята, это шедевр, идеально, трогать — только портить". Чтобы какой-нибудь умник не наследовался от него и не наделал в коде таких дел, что потом разгребать — овердохуища, нужно его запечатать. Кидаешь модификатор sealed и спишь спокойно.
Как это выглядит, блядь:
public sealed class ApiResponse
{
public string Data { get; set; }
public int StatusCode { get; set; }
}
// А вот тут уже попытка наследования вызовет такую ошибку компиляции, что мало не покажется:
// 'DerivedResponse': cannot derive from sealed type 'ApiResponse'
public class DerivedResponse : ApiResponse { }
А нахуя это вообще надо, спросишь?
- Чтобы дизайн не сломали, епта. Бывает класс с такой хитрой внутренней кухней (кэш там, синглтон, безопасность какая), что любое наследование — это гарантированный пиздец. Запечатал — и нет проблем.
- Чтобы быстрее работало, ядрёна вошь! Компилятор, видя
sealed, понимает: "А, так тут переопределений точно не будет!" И начинает вытворять такие оптимизации, что производительность взлетает. - Просто чтобы поставить точку. Чётко говоришь миру: "Эта ветка эволюции закончена, плодиться тут нечего".
А ещё есть фишка — можно не весь класс душить, а только отдельные методы, хитрая жопа! Допустим, базовый метод виртуальный, ты его переопределил, но дальше хочешь запретить мудохаться с ним.
public class PaymentProcessor
{
// Ну, обычный виртуальный метод, можно переопределять
public virtual void Validate() { /* общая логика */ }
}
public class CreditCardProcessor : PaymentProcessor
{
// Переопределили, но ВОТ ТУТ СТАВИМ ПЛОМБУ.
// Дальше никто в наследниках этот метод трогать не сможет.
public sealed override void Validate()
{
base.Validate();
// + своя специфичная проверка карты
}
}
public class PremiumCardProcessor : CreditCardProcessor
{
// А вот тут уже получишь по рукам: CS0239 — sealed метод переопределять низя!
// public override void Validate() { }
}
Вот и весь секрет. Хочешь полный контроль — запечатывай класс. Хочешь точечную защиту — запечатывай критические методы. И никаких распиздяйств!