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

В чем разница между абстрактным класом и интерфейсом

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

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

Абстрактный класс объявляется с ключевым словом abstract. Он может содержать как абстрактные методы (без реализации), так и обычные методы с реализацией, поля, свойства, конструкторы. Это позволяет задать общую логику для группы родственных классов. Например, абстрактный класс Aircraft может содержать поле MaxSpeed, реализацию метода StartEngine() и абстрактный метод Fly().

Интерфейс в C# объявляется с ключевым словом interface. До C# 8.0 интерфейсы могли содержать только сигнатуры методов, свойств, событий и индексаторов без реализации. Начиная с C# 8.0 появились методы с реализацией по умолчанию, но основное назначение интерфейса — определить контракт, который обязуется выполнить класс. Интерфейс не может содержать полей и конструкторов.

Пример

csharp
// Абстрактный класс
public abstract class Aircraft
{
    public int MaxSpeed { get; set; }

    public void StartEngine()
    {
        Console.WriteLine("Engine started");
    }

    // Абстрактный метод — должен быть реализован в наследнике
    public abstract void Fly();
}

// Интерфейс
public interface IFlyable
{
    void Fly();
}

// Класс может наследовать один абстрактный класс и несколько интерфейсов
public class Boeing : Aircraft, IFlyable
{
    public override void Fly()
    {
        Console.WriteLine("Boeing is flying");
    }
}

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

  • Множественное наследование: C# не поддерживает множественное наследование классов, поэтому класс может иметь только один базовый абстрактный класс. Интерфейсов можно реализовать сколько угодно. Это ключевое различие, которое часто определяет выбор.
  • Состояние: Абстрактный класс может хранить состояние (поля), интерфейс — нет. Если нужно передать общие данные, выбирайте абстрактный класс.
  • Реализация по умолчанию: В C# 8+ интерфейсы могут иметь реализацию по умолчанию, но это не делает их заменой абстрактных классов — они всё ещё не могут иметь полей.
  • Семантика: Абстрактный класс описывает «что это» (is-a), интерфейс — «что умеет» (can-do). Например, Aircraft — это тип, а IFlyable — способность.

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

Выбирайте абстрактный класс, когда:

  • Есть общая реализация, которую нужно переиспользовать в нескольких классах.
  • Нужны поля, конструкторы или модификаторы доступа (protected, private).
  • Классы логически связаны и образуют иерархию.

Выбирайте интерфейс, когда:

  • Нужно определить контракт для несвязанных классов (например, IComparable для сравнения).
  • Нужна поддержка множественного наследования поведения.
  • Нужно отделить определение API от реализации (например, для тестирования с моками).

Коротко

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