Static readonly или const в C#: что выбрать в 2025?

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

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

Представьте ситуацию: вы пишете код на C# и вам нужно объявить значение, которое не должно меняться. Первая мысль — const. Вторая — static readonly. А третья — «А какая, собственно, разница?».

Этот вопрос — один из самых популярных на Stack Overflow. Тысячи разработчиков, от новичков до сеньоров, продолжают спорить, что лучше. И в 2025 году, с выходом новых версий .NET и C# 13, этот выбор стал ещё интереснее.

В этой статье мы раз и навсегда разберёмся, когда использовать const, а когда — static readonly. Вы узнаете не только теорию, но и получите чёткие правила, которые сможете применить прямо сегодня.

Что скрывается за модификаторами?

const: жёсткая константа

Модификатор const в C# — это буквально «высеченное в камне» значение. Оно должно быть известно на этапе компиляции. Компилятор подставляет значение константы напрямую в код везде, где она используется.

public class MathConstants
{
    public const double Pi = 3.14159;
    public const int DaysInWeek = 7;
    public const string AppName = "MyApp";
}

Обратите внимание: const всегда неявно static. Вы не можете написать static const — компилятор выдаст ошибку.

static readonly: гибкая неизменность

Модификатор static readonly — это поле, которое инициализируется один раз и больше не меняется. Главное отличие: значение может быть вычислено во время выполнения программы.

public class AppSettings
{
    public static readonly DateTime ReleaseDate = new DateTime(2025, 1, 15);
    public static readonly Guid InstanceId = Guid.NewGuid();
    public static readonly string ConfigPath = GetConfigPath();
    
    private static string GetConfigPath()
    {
        return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "config.json");
    }
}

Ключевые различия: таблица для быстрого сравнения

Давайте разложим всё по полочкам в наглядной таблице:

Характеристика const static readonly
Время инициализации Компиляция Выполнение (статический конструктор)
Допустимые типы Только примитивные (int, double, string, enum, bool) Любые типы (включая ссылочные)
Память Значение копируется в каждый assembly Единая ссылка в памяти
Совместимость версий Проблемы при обновлении библиотек Безопасно
Производительность Максимальная (подстановка на этапе компиляции) Небольшой оверхед при первом обращении

Когда выбирать const?

Используйте const, когда:

  • Значение абсолютно неизменно — математические константы (π, e), количество дней в неделе, физические константы.
  • Значение должно быть доступно на этапе компиляции — например, для атрибутов, switch/case, параметров по умолчанию.
  • Вы контролируете весь код — и уверены, что библиотека не будет обновляться отдельно.
// Идеально для const
public class Physics
{
    public const double SpeedOfLight = 299792458; // м/с
    public const double GravitationalConstant = 6.67430e-11; // м³/(кг·с²)
}

// Использование в атрибуте — обязательно const
[Obsolete("Use " + nameof(NewMethod) + " instead")]
public void OldMethod() { }

Когда выбирать static readonly?

Отдавайте предпочтение static readonly в следующих случаях:

  • Значение вычисляется во время выполнения — GUID, дата запуска, путь к файлу конфигурации.
  • Сложные типы данных — массивы, списки, Dictionary, пользовательские классы.
  • Вы разрабатываете библиотеку — чтобы избежать проблем с версионированием.
  • Значение может измениться в будущем — но только через перекомпиляцию библиотеки (не кода клиента).
// Лучше использовать static readonly
public class AppInfo
{
    public static readonly DateTime BuildDate = File.GetCreationTimeUtc(typeof(AppInfo).Assembly.Location);
    public static readonly string[] SupportedLanguages = { "en", "ru", "de", "fr" };
    public static readonly Dictionary<string, int> HttpStatusCodes = new()
    {
        ["OK"] = 200,
        ["NotFound"] = 404,
        ["InternalServerError"] = 500
    };
}

Подводные камни const: история из реального проекта

Представьте: вы разрабатываете библиотеку MyLibrary.dll:

// Версия 1.0 библиотеки
public class Config
{
    public const int MaxRetries = 3;
    public const string DatabaseName = "prod_db";
}

Вы компилируете библиотеку и своё приложение. Всё работает. Через месяц вы решаете увеличить MaxRetries до 5. Вы обновляете библиотеку до версии 1.1, но забываете перекомпилировать приложение.

Что произойдёт? Приложение продолжит использовать значение 3! Потому что компилятор скопировал значение константы в код приложения на этапе компиляции. Библиотека обновилась, а приложение — нет.

С static readonly такой проблемы не возникнет — значение всегда читается из библиотеки во время выполнения.

Лучшие практики 2025 года

Правило 1: const — только для внутренних констант

Используйте const исключительно для значений, которые используются внутри одного класса или сборки. Если константа может понадобиться внешним потребителям — сделайте её static readonly.

Правило 2: public API — только static readonly

Все публичные неизменяемые значения в библиотеках и публичных API должны быть public static readonly. Это обеспечит правильное версионирование и гибкость.

Правило 3: Используйте readonly struct для сложных констант

В C# 13 вы можете создавать readonly struct, которые идеально подходят для группировки связанных констант:

public readonly struct DatabaseSettings
{
    public static readonly DatabaseSettings Default = new("                

Блоги

Рекомендаций по книгам