Ответ
Да, могут. В 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). Штука мощная, позволяет описать в интерфейсе контракт не только для экземпляров, но и для статики классов, которые его реализуют. Но это уже для особо изощрённых архитектурных извращений, когда простых констант уже мало.