В чем разница между const
и readonly
, а вы используете один над другим?
Помимо очевидной разницы
const
VS readonly
, можно вычислить динамически, но их необходимо назначить до того, как конструктор выйдет.. после этого он заморожен.static
. Для доступа к ним используется нотация ClassName.ConstantName
.Существует тонкая разница. Рассмотрим класс, определенный в AssemblyA
.
public class Const_V_Readonly
{
public const int I_CONST_VALUE = 2;
public readonly int I_RO_VALUE;
public Const_V_Readonly()
{
I_RO_VALUE = 3;
}
}
AssemblyB
ссылки AssemblyA
и используют эти значения в коде. Когда это скомпилировано,
const
, это похоже на find-replace, значение 2 "испечено" в AssemblyB
IL. Это означает, что если завтра я обновлю I_CONST_VALUE
до 20 в будущем. AssemblyB
все равно будет иметь 2, пока я его не перекомпилирую.readonly
, это похоже на ref
на ячейку памяти. Значение не запекается в AssemblyB
IL. Это означает, что, если местоположение памяти обновлено, AssemblyB
получает новое значение без перекомпиляции. Поэтому, если I_RO_VALUE
обновлено до 30, вам нужно построить AssemblyA
. Все клиенты не нуждаются в повторной компиляции.Итак, если вы уверены, что значение константы не изменится, используйте const
.
public const int CM_IN_A_METER = 100;
Но если у вас есть константа, которая может измениться (например, точность w.r.t.).. или если у вас есть сомнения, используйте readonly
.
public readonly float PI = 3.14;
Обновление: Аку нужно получить упоминание о том, что он указал на это первым. Также мне нужно подключить, где я это узнал. Эффективный С# - Билл Вагнер
static
точка кажется наиболее важной и полезной точкой - consts are implicitly static
Есть гоча с consts! Если вы ссылаетесь на константу из другой сборки, ее значение будет скомпилировано прямо в вызывающую сборку. Таким образом, когда вы обновляете константу в ссылочной сборке, она не будет изменяться в вызывающей сборке!
Просто для добавления, ReadOnly для ссылочных типов только делает ссылку только на чтение, а не значения. Например:
public class Const_V_Readonly
{
public const int I_CONST_VALUE = 2;
public readonly char[] I_RO_VALUE = new Char[]{'a', 'b', 'c'};
public UpdateReadonly()
{
I_RO_VALUE[0] = 'V'; //perfectly legal and will update the value
I_RO_VALUE = new char[]{'V'}; //will cause compiler error
}
}
string
который вы могли бы использовать в качестве константы?
const
с ссылочными типами, отличными от строки, но константа может иметь только значение null
.
Это объясняет это. Резюме: const должен быть инициализирован во время объявления, readonly может быть инициализирован конструктором (и, следовательно, имеет другое значение в зависимости от используемого конструктора).
EDIT: см. Gishu gotcha выше для тонкой разницы
const
: Невозможно изменить где-либо.
readonly
: Это значение может быть изменено только в конструкторе. Невозможно изменить в обычных функциях.
Существует небольшая магия с readonly. Поле readonly может быть установлено несколько раз внутри конструктора (-ов). Даже если значение задано в двух разных цепных конструкторах, оно все же разрешено.
public class Sample {
private readonly string ro;
public Sample() {
ro = "set";
}
public Sample(string value) : this() {
ro = value; // this works even though it was set in the no-arg ctor
}
}
Постоянный член определяется во время компиляции и не может быть изменен во время выполнения. Константы объявляются как поле, используя ключевое слово const
и должны быть инициализированы по мере их объявления.
public class MyClass
{
public const double PI1 = 3.14159;
}
A readonly
член как константа в том, что он представляет неизменное значение. Разница в том, что элемент readonly
может быть инициализирован во время выполнения, в конструкторе, а также может быть инициализирован по мере их объявления.
public class MyClass1
{
public readonly double PI2 = 3.14159;
//or
public readonly double PI3;
public MyClass2()
{
PI3 = 3.14159;
}
}
Const
static
(они неявно статичны)только для чтения
static const int i = 0;
const
не могут быть сделаны внутри методов?
A const - это константа времени компиляции, тогда как readonly позволяет вычислять значение во время выполнения и устанавливать в конструкторе или инициализаторе поля. Таким образом, константа const всегда постоянна, но "readonly" доступен только для чтения после ее назначения.
Эрик Липперт команды С# имеет больше информации о разных типах неизменяемости
Здесь еще одна ссылка, демонстрирующая, как const не является безопасным версией или релевантна для ссылочных типов.
Резюме:
Только для чтения: Значение может быть изменено с помощью Ctor во время выполнения. Но не через функцию-член
Константа: Дефект статический. Значение не может быть изменено нигде (Ctor, Function, runtime etc no-where)
Еще одно значение: значения readonly могут быть изменены с помощью "коварного" кода через отражение.
var fi = this.GetType()
.BaseType
.GetField("_someField",
BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, 1);
Могу ли я изменить приватное поле, наследуемое только для чтения, на С#, используя отражение?
Я считаю, что значение const
одно и то же для всех объектов (и должно быть инициализировано литераловым выражением), тогда как readonly
может быть различным для каждого экземпляра...
Один из членов команды в нашем офисе предоставил следующие рекомендации о том, когда использовать const, static и readonly:
Последнее замечание: константное поле статично, но инверсия неверна.
Они оба постоянные, но константа доступна также во время компиляции. Это означает, что один аспект различия заключается в том, что вы можете использовать константные переменные в качестве входных данных для конструкторов атрибутов, но не только для переменных.
Пример:
public static class Text {
public const string ConstDescription = "This can be used.";
public readonly static string ReadonlyDescription = "Cannot be used.";
}
public class Foo
{
[Description(Text.ConstDescription)]
public int BarThatBuilds {
{ get; set; }
}
[Description(Text.ReadOnlyDescription)]
public int BarThatDoesNotBuild {
{ get; set; }
}
}
Ключевое слово readonly отличается от ключевого слова const. Поле const может быть инициализировано только при объявлении поля. Поле readonly может быть инициализировано либо в объявлении, либо в конструкторе. Поэтому поля readonly могут иметь разные значения в зависимости от используемого конструктора. Кроме того, хотя поле const является константой времени компиляции, поле readonly может использоваться для констант времени выполнения, как в следующем примере:
public static readonly uint timeStamp = (uint)DateTime.Now.Ticks;
Ключевое слово readonly отличается от ключевого слова const. Поле const может быть инициализировано только при объявлении поля. Поле readonly может быть инициализировано либо в объявлении, либо в конструкторе. Поэтому поля readonly могут иметь разные значения в зависимости от используемого конструктора. Кроме того, хотя константное поле является константой времени компиляции, поле readonly может использоваться для констант времени выполнения, как в следующем примере:
public static readonly uint l1 = (uint) DateTime.Now.Ticks;
Переменные, отмеченные как const, представляют собой немного больше, чем строго типизированные макросы #define, во время компиляции ссылки на переменные const заменяются встроенными литеральными значениями. Таким образом, можно использовать только определенные встроенные примитивные типы значений. Переменные, помеченные как readonly, могут быть заданы в конструкторе во время выполнения, а их постоянная доступность также применяется во время выполнения. Существует несколько незначительных издержек, связанных с этим, но это означает, что вы можете использовать readonly с любыми типами (даже ссылочными типами).
Кроме того, константные переменные по своей сути являются статическими, тогда как переменные readonly могут быть конкретными, если это необходимо.
Значительная разница между полями const и readonly в С#.Net
const по умолчанию статический и должен быть инициализирован с постоянным значением, которое впоследствии не может быть изменено. Изменение значения также не допускается в конструкторах. Он не может использоваться со всеми типами данных. Для ex-DateTime. Он не может использоваться с типом данных DateTime.
public const DateTime dt = DateTime.Today; //throws compilation error
public const string Name = string.Empty; //throws compilation error
public readonly string Name = string.Empty; //No error, legal
readonly может быть объявлен как статический, но необязательный. Не нужно инициализировать во время объявления. Его значение может быть назначено или изменено с помощью конструктора. Таким образом, он дает преимущество при использовании в качестве члена класса экземпляра. Два разных экземпляра могут иметь другое значение поля readonly. Для ex -
class A
{
public readonly int Id;
public A(int i)
{
Id = i;
}
}
Затем поле readonly может быть инициализировано мгновенными конкретными значениями следующим образом:
A objOne = new A(5);
A objTwo = new A(10);
Здесь экземпляр objOne будет иметь значение поля readonly как 5, а objTwo - 10. Это невозможно при использовании const.
Другой gotcha.
Поскольку const действительно работает только с базовыми типами данных, если вы хотите работать с классом, вы можете почувствовать "принудительное" использование ReadOnly. Однако остерегайтесь ловушки! ReadOnly означает, что вы не можете заменить объект другим объектом (вы не можете заставить его ссылаться на другой объект). Но любой процесс, который имеет ссылку на объект, может свободно изменять значения внутри объекта!
Поэтому не следует путать, думая, что ReadOnly подразумевает, что пользователь не может ничего изменить. В С# нет простого синтаксиса, чтобы предотвратить изменение экземпляра класса из-за изменения его внутренних значений (насколько я знаю).
Constant
Нам нужно указать значение в поле const, когда оно определено. Затем компилятор сохраняет значение констант в метаданных сборки. Это означает, что константу можно определить только для примитивного типа типа boolean, char, byte и т.д. Константы всегда считаются статическими членами, а не членами экземпляра.
Readonly
Поля Readonly могут быть разрешены только во время выполнения. Это означает, что мы можем определить значение для значения, используя конструктор для типа, в котором объявлено поле. Проверка выполняется компилятором, что поля readonly не записываются каким-либо другим методом, кроме конструктора.
Подробнее о объясняется здесь в этой статье
Константа будет скомпилирована в потребитель как литеральное значение, в то время как статическая строка будет служить ссылкой на определенное значение.
В качестве упражнения попробуйте создать внешнюю библиотеку и использовать ее в консольном приложении, затем измените значения в библиотеке и перекомпилируйте ее (без перекомпиляции потребительской программы), отбросьте DLL в каталог и запустите EXE вручную, вы должны обнаружить, что константная строка не изменяется.
Поле const может быть инициализировано только при объявлении поля. Поле readonly может быть инициализировано либо в объявлении, либо в конструкторе.
Константные переменные объявляются и инициализируются во время компиляции. Значение не может быть изменено после опекунов. Переменные только для чтения будут инициализированы только из конструктора Static класса. Только чтение используется только тогда, когда мы хотим присвоить значение во время выполнения.
Разница заключается в том, что значение статического поля readonly устанавливается во время выполнения, поэтому оно может иметь другое значение для разных исполнений программы. Однако значение константного поля задается постоянной времени компиляции.
Помните: Для ссылочных типов в обоих случаях (статический и экземпляр) модификатор только для чтения запрещает вам назначать новую ссылку на это поле. Он специально не делает неизменным объект, на который указывает ссылка.
Подробнее см. в разделе Часто задаваемые вопросы по С# на эту тему: http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx
ReadOnly: значение будет инициализировано только один раз из конструктора класса.
const: может быть инициализирована в любой функции, но только один раз
Const и readonly похожи, но они не совсем то же самое. Поле const является константой времени компиляции, что означает, что это значение может быть вычислено во время компиляции. Поле readonly позволяет создавать дополнительные сценарии, в которых некоторый код должен выполняться во время построения типа. После построения поле readonly не может быть изменено.
Например, члены константы могут использоваться для определения членов типа:
struct Test
{
public const double Pi = 3.14;
public const int Zero = 0;
}
так как значения, такие как 3.14 и 0, являются константами времени компиляции. Однако рассмотрите случай, когда вы определяете тип и хотите предоставить некоторые предварительные экземпляры. Например, вы можете определить класс "Цвет" и предоставить "константы" для общих цветов, таких как "Черный", "Белый" и т.д. Это невозможно сделать с помощью константных членов, поскольку правые части не являются константами времени компиляции. Это можно сделать с помощью обычных статических элементов:
public class Color
{
public static Color Black = new Color(0, 0, 0);
public static Color White = new Color(255, 255, 255);
public static Color Red = new Color(255, 0, 0);
public static Color Green = new Color(0, 255, 0);
public static Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(byte r, byte g, byte b) {
red = r;
green = g;
blue = b;
}
}
но тогда нет ничего, что могло бы помешать клиенту Color отбрасывать его, возможно, путем замены значений черного и белого. Излишне говорить, что это вызовет ужас для других клиентов класса Color. Функция "только для чтения" рассматривает этот сценарий. Просто введя ключевое слово readonly в объявлениях, мы сохраняем гибкую инициализацию, не мешая клиентскому коду.
public class Color
{
public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color White = new Color(255, 255, 255);
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(byte r, byte g, byte b) {
red = r;
green = g;
blue = b;
}
}
Интересно отметить, что константные члены всегда статичны, тогда как член readonly может быть либо статичным, либо нет, как обычное поле.
Можно использовать одно ключевое слово для этих двух целей, но это приводит либо к проблемам с версией, либо к проблемам с производительностью. Предположим на мгновение, что мы использовали одно ключевое слово для этого (const), а разработчик написал:
public class A
{
public static const C = 0;
}
а другой разработчик написал код, основанный на A:
public class B
{
static void Main() {
Console.WriteLine(A.C);
}
}
Теперь, может ли генерируемый код полагаться на то, что A.C является константой времени компиляции? I.e., можно ли использовать A.C просто заменить на значение 0? Если вы говорите "да", то это означает, что разработчик A не может изменить способ инициализации A.C - это связывает руки разработчика A без разрешения. Если вы скажете "нет" на этот вопрос, тогда будет пропущена важная оптимизация. Возможно, автор A положителен, что A.C всегда будет равным нулю. Использование как const, так и readonly позволяет разработчику A указать намерение. Это улучшает поведение версий, а также повышает производительность.
A const
должен быть жестко закодирован, где readonly
может быть установлен в конструкторе класса.
В принципе; вы можете присвоить значение статическому полю readonly неизменному значению во время выполнения, тогда как константе должно быть присвоено постоянное значение.
Проще говоря, Const - это время компиляции, а readonly - это время выполнения.
Ключевым отличием является то, что Const является эквивалентом С#DEFINE. Число буквально получает замену a-la precompiler. Readonly фактически рассматривается как переменная.
Это различие особенно актуально, если у вас есть проект А, зависящий от общедоступной константы из проекта В. Предположим, что переменная public изменяется. Теперь ваш выбор const/readonly будет влиять на поведение в проекте A:
Const: проект A не захватывает новое значение (если оно не перекомпилировано с новым const, конечно), потому что оно было скомпилировано с константами, которые были заменены.
ReadOnly: Project A всегда будет запрашивать проект B для его значения переменной, поэтому он получит новое значение публичной константы в B.
Честно говоря, я бы рекомендовал использовать readonly почти для всего, кроме действительно универсальных констант (например, Pi, Inches_To_Centimeters). Для всего, что может измениться, я говорю, что использую только для чтения.
Надеюсь, это поможет, Алан.
Одна вещь, чтобы добавить к тому, что люди сказали выше. Если у вас есть сборка, содержащая значение readonly (например, readonly MaxFooCount = 4;), вы можете изменить значение, которое вызывает вызовы сборок, отправив новую версию этой сборки с другим значением (например, только для чтения MaxFooCount = 5;)
Но с константой он будет свернут в код вызывающего абонента, когда вызывающий был скомпилирован.
Если вы достигли уровня владения С#, вы готовы к книге Билла Вагнера, Эффективная С#: 50 конкретных способов улучшить ваш С# Ответ на этот вопрос подробно (и еще 49 вещей).