В чем разница между const и readonly в C#?
Ключевое различие: время вычисления и область применения
Главное отличие между const и readonly в C# — это когда значение фиксируется и как оно обрабатывается компилятором.
const — константа времени компиляции
const означает, что значение должно быть известно на этапе компиляции. Оно подставляется непосредственно в код (как литерал).
public class Calculator
{
public const double Pi = 3.14159;
public const int DaysInWeek = 7;
// public const DateTime Now = DateTime.Now; // Ошибка! Нельзя использовать неконстантное выражение
}
Ограничения const:
- Можно использовать только с примитивными типами (
int,double,bool,string,enum). - Значение должно быть вычислено на этапе компиляции.
- Нельзя инициализировать в конструкторе — только при объявлении.
- По умолчанию
static(нельзя использоватьstatic const— это избыточно).
readonly — константа времени выполнения
readonly фиксирует значение один раз во время выполнения — либо при объявлении, либо в конструкторе класса.
public class DatabaseConfig
{
public readonly string ConnectionString;
public readonly int MaxRetries;
public DatabaseConfig(string connectionString, int maxRetries)
{
ConnectionString = connectionString; // Можно задать в конструкторе
MaxRetries = maxRetries;
}
// public void Update() { ConnectionString = "new"; } // Ошибка! Нельзя изменить после конструктора
}
Особенности readonly:
- Работает с любыми типами данных (включая ссылочные).
- Может быть инициализирован в конструкторе (это дает гибкость).
- Может быть статическим или экземплярным.
- Не обязан быть константой компиляции — можно использовать
DateTime.Now, результат метода и т.д.
Практические примеры
Рассмотрим сценарий, где разница становится критичной:
// Библиотека ClassLibrary.dll
public class Constants
{
public const int Version = 1;
public static readonly int BuildNumber = 100;
}
// Приложение, использующее библиотеку
Console.WriteLine(Constants.Version); // Всегда 1, даже если библиотека обновлена
Console.WriteLine(Constants.BuildNumber); // Обновится, если перекомпилировать библиотеку
Если вы измените const в библиотеке и не перекомпилируете приложение, приложение продолжит использовать старое значение (потому что оно было "вклеено" в IL-код). readonly же читается из сборки каждый раз.
Когда что использовать?
- const — для абсолютно неизменных значений, которые никогда не поменяются:
Math.PI, количество дней в неделе, магические числа. - readonly — для значений, которые задаются один раз, но могут зависеть от внешних факторов: строка подключения, конфигурация, идентификатор экземпляра.
- static readonly — для "глобальных" констант, которые могут измениться в новой версии (например, номер версии приложения).
Важное замечание про ссылочные типы
readonly защищает только ссылку, но не содержимое объекта:
public class Config
{
public readonly List<string> AllowedUsers = new List<string>();
}
// Можно делать:
config.AllowedUsers.Add("Admin"); // OK! Ссылка не меняется
// Нельзя:
config.AllowedUsers = new List<string>(); // Ошибка! Нельзя переназначить
Итог: const — это жесткая подстановка на этапе компиляции, readonly — защита от записи после инициализации в рантайме.
Дополнение: производительность и метаданные
Коллега выше отлично объяснил основную разницу. Я добавлю несколько технических нюансов, которые помогут глубже понять тему.
Производительность
const немного быстрее, потому что значение подставляется непосредственно в код на этапе компиляции — нет необходимости в чтении из памяти. Однако разница обычно микроскопическая и не стоит того, чтобы жертвовать гибкостью.
Атрибуты и метаданные
const не создает поле в классе — оно существует только в метаданных как константа. readonly же создает полноценное поле, которое можно увидеть через рефлексию:
public class Test
{
public const int A = 1;
public readonly int B = 2;
}
// Через рефлексию:
var fields = typeof(Test).GetFields();
// fields содержит B, но НЕ содержит A!
Инициализация в конструкторе
Это ключевое отличие: readonly можно задать в конструкторе, что позволяет создавать разные экземпляры с разными "константами":
public class User
{
public readonly DateTime CreatedAt;
public User() => CreatedAt = DateTime.UtcNow; // Уникальное время для каждого объекта
}
С const такое невозможно — значение будет одинаковым для всех экземпляров и всех сборок.
Практический совет
Если сомневаетесь — используйте static readonly. Это безопаснее и гибче, чем const. const стоит применять только для действительно неизменных величин, определенных в стандартах (например, Math.PI).
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги