Могут ли в интерфейсе C# быть поля (fields)?

Ответ

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

Что может содержать интерфейс:

  • Методы (включая методы расширения)
  • Свойства (автореализуемые или с явными get/set-аксессорами)
  • События (event)
  • Индексаторы (this[])

Пример допустимого содержимого интерфейса:

public interface ILoggable
{
    // Свойство — это допустимо (по сути, методы get/set).
    string Id { get; }

    // Метод — это допустимо.
    void Log(string message);

    // Событие — это допустимо.
    event EventHandler OnLogged;

    // Статическое поле/константа — допустимо (начиная с C# 8.0).
    static readonly string DefaultCategory = "General";
    const int MaxEntries = 1000;
}

Почему поля недопустимы? Поле — это данные. Разрешение полей в интерфейсе означало бы навязывание конкретной реализации хранения данных, что нарушает принцип абстракции. Если вам нужно обязать реализующий класс иметь определенное поле, используйте абстрактный класс.

// Абстрактный класс МОЖЕТ содержать поля.
abstract class AbstractExample
{
    protected int _value; // Поле — допустимо.
}

Важно: Начиная с C# 8.0, интерфейсы поддерживают статические члены, включая статические поля и методы, но это по-прежнему не поля экземпляра.

Ответ 18+ 🔞

Да ты что, серьёзно? Ну блядь, вот сидишь такой, думаешь: "Сейчас я накидаю в интерфейс полей, и все классы будут их таскать, красота!" А нихуя! Нельзя так, нахуй!

Интерфейс в C# — это как договор, понимаешь? Контракт, ёпта. Ты обязуешься реализовать определённые штуки, а как ты это сделаешь внутри — твои проблемы. А поля — это уже внутренняя кухня, данные, состояние объекта. Это как если бы в договоре на поставку пива тебе ещё и холодильник в придачу прописывали — нихуя не гибко.

Что же можно в интерфейс пихнуть, спросишь? Да нормальные вещи:

  • Методы (ну это святое).
  • Свойства (это по сути те же методы get/set, так что ок).
  • События (event — тоже окей).
  • Индексаторы (this[] — да и такое бывает).

Вот, смотри, как выглядит приличный интерфейс:

public interface ILoggable
{
    // Свойство — можно, это ж по факту геттер.
    string Id { get; }

    // Метод — можно, это основа основ.
    void Log(string message);

    // Событие — можно, почему бы и нет.
    event EventHandler OnLogged;

    // Статическое поле или константа — можно (с C# 8.0).
    static readonly string DefaultCategory = "General";
    const int MaxEntries = 1000;
}

Видишь? Ни одного обычного поля экземпляра! Потому что если разрешить поля, то это уже будет не абстракция, а диктат, блядь. "Храни данные вот так!" — а если классу это неудобно? Пиздец тогда.

Так что же делать, если очень хочется обязать класс иметь поле? Да используй абстрактный класс, ебать! Он для этого и придуман.

// А вот абстрактный класс — другое дело, тут поля пожалуйста.
abstract class AbstractExample
{
    protected int _value; // Поле — да на здоровье, хуле.
}

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