Встречается на 88% собеседований по C#

В чём разница абстрактного класса и интерфейса

Абстрактный класс и интерфейс — это два механизма наследования и полиморфизма в C#, которые отличаются по назначению и возможностям. Абстрактный класс — это класс, от которого нельзя создать экземпляр, он может содержать как абстрактные, так и реализованные члены, а интерфейс — это контракт, который определяет только сигнатуры членов, без реализации. Основное различие: класс может наследовать только один абстрактный класс, но реализовывать множество интерфейсов.

Как это работает

Абстрактный класс используется для описания общего поведения и состояния подклассов. Он может содержать поля, конструкторы, методы с реализацией и абстрактные методы (без реализации). Подклассы обязаны реализовать все абстрактные методы, но наследуют реализованные члены.

csharp
public abstract class Животное
{
    public abstract void Есть(); // Абстрактный метод, должен быть реализован в наследнике.

    public void Дышать() // Метод с реализацией, наследуется всеми наследниками.
    {
        Console.WriteLine("Дыхание");
    }
}

Интерфейс определяет контракт, который классы или структуры могут реализовывать. Он содержит только объявления методов, свойств, событий, но не их реализации. Класс, реализующий интерфейс, должен предоставить реализацию для всех его членов.

csharp
public interface IЖивотное
{
    void Есть(); // Метод, который должен быть реализован в классе.
}

Основные различия

КритерийАбстрактный классИнтерфейс
НаследованиеКласс может наследовать только один абстрактный класс (одиночное наследование)Класс может реализовывать множество интерфейсов (множественное наследование)
ЧленыМожет содержать поля, конструкторы, методы с реализацией и абстрактные методыМожет содержать только объявления методов, свойств, событий; без полей и реализации
Конструкторы и деструкторыМожет иметь конструкторы и деструкторыНе может иметь конструкторов и деструкторов
Модификаторы доступаМожно использовать различные модификаторы доступа (public, protected, private и т.д.)Все члены по умолчанию public, нельзя указать другой модификатор

Когда использовать

Абстрактный класс применяется, когда классы-наследники имеют много общего и должны наследовать некоторую реализацию. Например, базовый класс для всех животных с общим методом Дышать. Интерфейс подходит для определения общего контракта для классов, которые могут не иметь общей реализации. Например, интерфейс IЖивотное может быть реализован и классом Собака, и классом Кот, но они не обязаны иметь общую реализацию.

Подводные камни

  • В C# до версии 8 интерфейсы не могли содержать реализацию по умолчанию. С C# 8 появились методы с реализацией по умолчанию, но это не отменяет основного различия: интерфейс — это контракт, а абстрактный класс — это частичная реализация.
  • Нельзя создавать экземпляр ни абстрактного класса, ни интерфейса.
  • Абстрактный класс может содержать поля, а интерфейс — нет. Если нужно хранить состояние, выбирайте абстрактный класс.
  • При наследовании от абстрактного класса наследник получает все члены, включая реализованные. При реализации интерфейса класс должен реализовать все члены, даже если они не нужны.

Коротко

  • Абстрактный класс — это частичная реализация, интерфейс — контракт без реализации.
  • Одиночное наследование для абстрактного класса, множественное — для интерфейсов.
  • Абстрактный класс может иметь поля, конструкторы и реализованные методы; интерфейс — только сигнатуры.
  • Выбирайте абстрактный класс для общей базы с реализацией, интерфейс — для определения общего поведения у несвязанных классов.
как отвечать на вопрос
пример собеседования
фреймворки на собеседовании
типичные вопросы junior
интервью вопросы и ответы