Ответ
Эти модификаторы решают разные задачи, связанные с областью видимости, временем инициализации и принадлежностью данных.
const (константа времени компиляции)
- Значение должно быть известно на этапе компиляции.
- Инициализация: Только при объявлении.
- Неявно
static: Обращение через имя класса:ClassName.ConstName. - Типы данных: Только встроенные типы (
int,double,bool,char,string). - Пример:
public class MathConstants { public const double Pi = 3.14159; public const string AppName = "MyApp"; } // Использование: double circumference = 2 * MathConstants.Pi * radius;
readonly (константа времени выполнения)
- Значение может быть вычислено во время выполнения.
- Инициализация: При объявлении или в конструкторе класса (для полей экземпляра).
- Может быть
staticили нет. - Типы данных: Любые.
-
Пример:
public class AppService { public readonly DateTime StartTime = DateTime.Now; // Инициализация при объявлении private readonly ILogger _logger; public AppService(ILogger logger) { _logger = logger; // Инициализация в конструкторе } }
static (принадлежность типу)
- Указывает, что член (поле, свойство, метод) принадлежит самому типу (классу), а не его экземплярам.
- Комбинируется с
readonly:static readonly— распространённая практика для констант времени выполнения на уровне класса. -
Пример:
public class Configuration { // Константа времени выполнения, общая для всех экземпляров и потоков. public static readonly string ConnectionString = LoadFromConfig(); public static int InstanceCount { get; private set; } // Статическое свойство public Configuration() { InstanceCount++; } }
| Сводная таблица: | Критерий | const |
readonly (поле экземпляра) |
static readonly |
|---|---|---|---|---|
| Время инициализации | Компиляция | Выполнение (в конструкторе) | Выполнение (статический конструктор) | |
| Принадлежность | Классу (static) |
Экземпляру класса | Классу (static) |
|
| Допустимые типы | Примитивы, string |
Любые | Любые | |
| Изменяемость | Никогда | Только в конструкторе | Только в статическом конструкторе |
Ответ 18+ 🔞
Давай разберём эту триаду, а то народ постоянно путается, будто это три одинаковые хуйни. А там, блядь, разница — как между "выпить чаю" и "получить по ебалу чайником".
const — это как татуха на жопе, на всю жизнь
Значение должно быть известно прямо на этапе компиляции, вот прямо когда ты код пишешь. Как будто ты объявляешь: "Пи — это 3.14, и точка нахуй". Менять потом — только с кожей срезать, перекомпилировать весь проект.
- Инициализация: Только тут же, в момент объявления. Позже — ни-ни.
- Неявно
static: Обращаешься к ней через имя класса, типаMathConstants.Pi. Экземпляр для этого дерьма не нужен. - Типы: Только примитивы (
int,bool) даstring. Сложные объекты сюда не впихнёшь. - Пример, чтобы было понятно:
public class Settings { public const int MaxRetryCount = 3; // Всё, тройка навеки в камне. public const string AppName = "MySuperApp"; // И название не поменять. } // Используется везде просто по имени класса for (int i = 0; i < Settings.MaxRetryCount; i++) { ... }
readonly — это как обещание, которое даёшь один раз
Значение можно вычислить уже во время работы программы. Дал слово — и держишь. Менять можно только в одном месте — в конструкторе того класса, где поле объявлено. После этого — всё, пиши пропало, поле заморожено.
- Инициализация: Или сразу при объявлении, или в любом конструкторе этого класса. Больше нигде.
- Может быть как обычным полем экземпляра, так и статическим (
static readonly). - Типы: Любые, хоть целый
List<string>тули. -
Пример из жизни:
public class OrderProcessor { // Вычислили при создании объекта и зафиксировали public readonly DateTime OrderCreated = DateTime.Now; // Получили извне при создании и больше не трогаем private readonly IPaymentGateway _gateway; public OrderProcessor(IPaymentGateway gateway) { _gateway = gateway; // Вот здесь инициализируем, и всё. } // А вот так НЕЛЬЗЯ, будет ошибка: // public void ChangeGateway() { _gateway = newGateway; } }
static — это общая табличка на всех, а не личная кружка
Это вообще про другое. Говорит, что член (поле, метод, свойство) принадлежит не какому-то отдельному объекту, а всему классу целиком. Как общий холодильник на этаже. Один на всех.
- Часто комбинируется с
readonly: Получаетсяstatic readonly— идеальная штука для глобальных настроек, которые вычисляются при старте программы и потом не меняются. -
Пример, где всё вместе:
public class GlobalConfig { // Константа времени КОМПИЛЯЦИИ, общая для всех. public const string Version = "1.0"; // Константа времени ВЫПОЛНЕНИЯ, общая для всех. Инициализируется при первом обращении к классу. public static readonly string ConnectionString = LoadFromSecretsVault(); // Просто статическое поле, которое МОЖНО менять (обычно не стоит). public static int TotalRequestsProcessed = 0; }
Краткая шпаргалка, чтобы не еб... не путаться:
| Признак | const |
readonly (поле объекта) |
static readonly |
|---|---|---|---|
| Когда значение фиксируется | При компиляции | При создании объекта (в конструкторе) | При первом обращении к классу |
| Чьё это | Класса (неявно static) |
Конкретного экземпляра объекта | Класса (явно static) |
| Какие типы можно | Примитивы, string |
Любые, хоть HttpClient |
Любые |
| Можно ли изменить | Никогда, только пересобрать проект | Только в конструкторе этого класса | Только в статическом конструкторе |
Итог простой:
- Нужна жёсткая константа, известная при написании кода (число, флаг, название) —
const. - Нужно зафиксировать значение, которое узнаёшь только при запуске или передаёшь извне в объект —
readonly. - Нужно, чтобы это значение было одно на все экземпляры класса — добавляешь
staticкreadonly.
Вот и вся магия. Главное — не пытаться const присвоить DateTime.Now или результат вызова метода, а то компилятор тебе такое в уши надует, что мало не покажется.