Могут ли в интерфейсе храниться константы?

Ответ

Да, могут. В C# интерфейсы могут содержать константы (const) и статические поля только для чтения (static readonly). Эти члены неявно являются public, static и sealed (для констант).

Практический пример:

public interface IAppSettings
{
    const int MaxRetryCount = 3;
    static readonly string DefaultCulture = "en-US";
    static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(30);
}

// Использование:
int maxTries = IAppSettings.MaxRetryCount;
string culture = IAppSettings.DefaultCulture;

Ключевые особенности:

  • Константы (const) компилируются непосредственно в вызывающий код как литеральные значения. Изменение значения константы требует перекомпиляции всех зависимых сборок.
  • Статические поля (static readonly) являются ссылками, их значения хранятся в памяти и могут быть инициализированы в статическом конструкторе.
  • Обращаться к ним можно только через имя интерфейса (IAppSettings.MaxRetryCount), а не через экземпляр класса.

Современная альтернатива (C# 8.0+): Для более гибкого дизайна API рассмотрите использование статических абстрактных членов в интерфейсах (feature static abstract в интерфейсах), которые позволяют определять контракты для статических членов, реализуемых классами.

Ответ 18+ 🔞

А, ну ты про это! Да, конечно, могут, чё уж там. В C# интерфейсы — они не только про методы и свойства, они и про вот эту вот статическую фигню. Могут содержать константы (const) и статические поля только для чтения (static readonly). И все эти члены по умолчанию public, static и запечатаны, как банка с огурцами.

Смотри, как это выглядит на практике:

public interface IAppSettings
{
    const int MaxRetryCount = 3;
    static readonly string DefaultCulture = "en-US";
    static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(30);
}

// Используется это просто, блядь:
int maxTries = IAppSettings.MaxRetryCount;
string culture = IAppSettings.DefaultCulture;

А теперь главные подводные камни, чтобы ты не обосрался потом:

  • Константы (const) — это как татуировка на этапе компиляции. Значение вшивается прямо в код, куда её используют. Захотел поменять число — пересобирай всё, что на это число завязано, иначе будут одни расхождения, пиздец.
  • Статические поля (static readonly) — уже полегче, это ссылки, живут в памяти. Их можно инициализировать в статическом конструкторе, если надо посложнее логику запилить.
  • И главное, запомни, как Отче наш: обращаешься к этой статике только через имя самого интерфейса (IAppSettings.MaxRetryCount). Через объект какого-нибудь класса, который этот интерфейс реализует, — нихуя не выйдет, компилятор тебя пошлёт.

Ну и если ты уже в тренде и на C# 8.0+, то там вообще веселуха началась. Появились статические абстрактные члены в интерфейсах (этот static abstract). Штука мощная, позволяет описать в интерфейсе контракт не только для экземпляров, но и для статики классов, которые его реализуют. Но это уже для особо изощрённых архитектурных извращений, когда простых констант уже мало.