Как часто используются абстрактные классы
Что проверяют
Понимаете ли вы, чем абстрактный класс отличается от интерфейса в современном C# и почему в прикладном коде их стало меньше. Следом почти всегда спрашивают: «Что выберете, интерфейс или абстрактный класс, и почему?»
Как отвечать
Честный ответ: реже, чем интерфейсы. DI-контейнер в ASP.NET Core и моки работают с интерфейсами, а с C# 8 интерфейс может содержать реализацию по умолчанию. Но назовите, где вы встречаете абстрактные классы каждый день:
ControllerBase: база контроллеров ASP.NET Core;BackgroundService: реализуетIHostedService, а вам оставляет один абстрактныйExecuteAsync(CancellationToken). Шаблонный метод в чистом виде;JsonConverter<T>,DelegatingHandler,Stream: общая логика внутри, точки расширения черезabstractиvirtual;AbstractValidator<T>: база валидаторов в FluentValidation.
Дальше разница по существу:
- состояние: у абстрактного класса есть поля и конструкторы, у интерфейса полей экземпляра нет даже с методами по умолчанию;
- наследование: базовый класс один, интерфейсов сколько угодно;
- доступ:
protected-члены иprotected-конструктор бывают только у класса; - эволюция: метод с реализацией в абстрактном классе добавляется без поломки наследников. Методы интерфейсов по умолчанию требуют .NET Core 3.0 и новее, на .NET Framework их нет.
Правило выбора: интерфейс описывает, что тип умеет, абстрактный класс даёт общую реализацию и состояние родственным типам. Часто их сочетают: интерфейс для контракта, абстрактный класс как основа реализаций.
Где спотыкаются
Заводят BaseService или BaseRepository<T>, куда годами сваливается всё подряд. Наследники тянут лишние зависимости, а правка базы ломает десятки классов. Композиция здесь обычно лучше.
Вызывают virtual или abstract метод из конструктора базы. Вызов дойдёт до переопределения раньше, чем выполнится тело конструктора наследника: инициализаторы полей в C# уже отработали, а всё, что наследник присваивает в конструкторе, ещё пустое.
Отвечают «интерфейс без реализации, абстрактный класс с реализацией», как будто C# 8 не выходил.