В чем разница между const и readonly в C#? Когда что использовать?
Основные отличия между const и readonly
На первый взгляд const и readonly действительно похожи — оба делают переменную неизменяемой после инициализации. Однако они работают на совершенно разных уровнях и предназначены для разных сценариев. Давайте разберём ключевые различия.
1. Время инициализации
const — это константа времени компиляции. Её значение должно быть известно на момент компиляции и не может зависеть от вычислений во время выполнения. readonly — это константа времени выполнения. Её значение устанавливается один раз — либо при объявлении, либо в конструкторе класса.
public class Constants
{
// const — обязательно значение известно на этапе компиляции
public const int DaysInWeek = 7;
public const double Pi = 3.14159;
// public const DateTime Now = DateTime.Now; // ОШИБКА! Нельзя
// readonly — можно вычислить в конструкторе
public readonly DateTime CreationTime;
public readonly int RandomValue;
public Constants()
{
CreationTime = DateTime.Now; // OK
RandomValue = new Random().Next(100); // OK
}
}
2. Статическая природа
const по своей сути является статическим. Вы не можете использовать модификатор static вместе с const — это приведёт к ошибке компиляции. readonly может быть как статическим, так и экземплярным.
public class Example
{
// const всегда static, даже без ключевого слова
public const int A = 1; // Эквивалентно public static const int A = 1;
// readonly может быть разным для разных экземпляров
public readonly int InstanceValue;
public static readonly int StaticValue = 100;
public Example(int val)
{
InstanceValue = val; // Каждый объект может иметь своё значение
}
}
3. Поведение при компиляции
Это самое важное различие. const встраивается прямо в код на этапе компиляции. Если вы используете константу из другой сборки, её значение копируется в вашу сборку. readonly — это ссылка на поле, которая разрешается во время выполнения.
// Библиотека Version1.dll
public class Library
{
public const int Version = 1;
public static readonly int ReadonlyVersion = 1;
}
// Ваше приложение
Console.WriteLine(Library.Version); // Будет встроено как Console.WriteLine(1)
Console.WriteLine(Library.ReadonlyVersion); // Будет обращение к полю
Если вы обновите библиотеку до версии 2, изменив Version = 2 и ReadonlyVersion = 2, то:
Library.Versionв вашем приложении всё равно покажет 1, пока вы не перекомпилируете его.Library.ReadonlyVersionпокажет 2 сразу после замены DLL, без перекомпиляции.
4. Типы данных
const может быть только для примитивных типов: bool, int, double, string, enum и null для ссылочных типов. readonly может быть любого типа, включая пользовательские классы, массивы и коллекции.
public class TypesDemo
{
// const — только примитивные типы
public const string AppName = "MyApp";
public const int MaxUsers = 100;
// public const List<string> Names = new List<string>(); // ОШИБКА!
// readonly — любые типы
public readonly List<string> Names = new List<string>(); // OK
public readonly StringBuilder Builder = new StringBuilder(); // OK
}
Когда что использовать?
- const — для значений, которые абсолютно неизменны и известны на этапе компиляции: математические константы (Pi, e), строковые литералы для путей, ключи, которые не будут меняться.
- readonly — для значений, которые устанавливаются один раз, но могут зависеть от внешних данных: время создания объекта, настройки из конфигурации, значения, полученные из базы данных.
- static readonly — для глобальных неизменяемых данных, которые могут измениться в новой версии библиотеки (чтобы не перекомпилировать клиентов).
Итоговая таблица
| Характеристика | const | readonly |
|---|---|---|
| Время вычисления | Компиляция | Выполнение |
| Статический | Всегда | Опционально |
| Изменение в конструкторе | Нет | Да |
| Поддерживаемые типы | Примитивные + string | Любые |
| Встраивание в код | Да | Нет (ссылка) |
Дополнение: readonly для структур и массивов
Хочу добавить важный нюанс, который часто путает новичков. Модификатор readonly гарантирует, что ссылку на объект нельзя изменить, но сам объект может быть изменяемым. Это особенно заметно с массивами и коллекциями.
public class ReadonlyDemo
{
public readonly int[] Numbers = { 1, 2, 3 };
public void TryModify()
{
// Numbers = new int[] { 4, 5, 6 }; // ОШИБКА! Нельзя переназначить
Numbers[0] = 100; // Это РАБОТАЕТ! Массив изменяется
}
}
То же самое касается полей readonly структур. Если у вас структура с изменяемыми полями, readonly защищает только от замены всей структуры целиком, но не от изменения её внутренних полей. Поэтому для настоящей неизменяемости рекомендуется использовать readonly struct (доступно с C# 7.2) или неизменяемые коллекции (ImmutableArray, ImmutableList).
Ещё один совет: если вы используете const для публичных членов библиотеки, помните о проблеме встраивания. Для публичного API лучше использовать static readonly, чтобы клиенты автоматически получали новые значения при обновлении библиотеки, без необходимости перекомпиляции.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги