В чем разница между константой и readonly?

В чем разница между const и readonly и вы используете ее над другой?

Помимо очевидной разницы

  • обязательство объявить значение во время определения для readonly значений readonly VS может быть вычислено динамически, но должно быть назначено до того, как конструктор завершит работу .. после этого он будет заморожен.
  • «const» неявно static . Для доступа к ним используется нотация ClassName.ConstantName .

Существует тонкая разница. Рассмотрим class, определенный в 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 «запекается» в IL AssemblyB . Это означает, что если завтра я буду обновлять I_CONST_VALUE до 20 в будущем. AssemblyB все равно будет 2, пока я не перекомпиляю его .
  • в случае значения readonly это похоже на ref на ячейку памяти. Значение не запекается в IL-ов AssemblyB . Это означает, что, если местоположение памяти обновлено, AssemblyB получает новое значение без перекомпиляции. Поэтому, если I_RO_VALUE обновлен до 30, вам нужно только собрать AssemblyA . Все клиенты не нуждаются в повторной компиляции.

Поэтому, если вы уверены, что значение константы не изменится, используйте константу.

 public const int CM_IN_A_METER = 100; 

Но если у вас есть константа, которая может измениться (например, точность) или если вы сомневаетесь, используйте readonly .

 public readonly float PI = 3.14; 

Обновление: Аку нужно получить упоминание о том, что он указал на это в первую очередь. Также мне нужно подключить, где я это узнал. Эффективный C # – Билл Вагнер

У меня есть сочленя! Если вы ссылаетесь на константу из другой сборки, ее значение будет скомпилировано прямо в вызывающую сборку. Таким образом, когда вы обновляете константу в указанной сборке, она не изменится в вызывающей сборке!

Константы

  • Константы по умолчанию статичны
  • Они должны иметь значение во время компиляции (вы можете иметь, например, 3.14 * 2, но не можете вызывать методы)
  • Может быть объявлено в рамках функций
  • Скопируются в каждую сборку, которая их использует (каждая assembly получает локальную копию значений)
  • Может использоваться в атрибутах

Поля экземпляров Readonly

  • Должен иметь установленное значение, к тому времени, когда конструктор завершает работу
  • Оцениваются при создании экземпляра

Статические поля readonly

  • Оцениваются, когда выполнение кода попадает в ссылку на class (когда создается новый экземпляр или выполняется статический метод)
  • Должно быть оцененное значение к моменту завершения статического конструктора
  • Не рекомендуется помещать ThreadStaticAttribute в эти (статические конструкторы будут выполняться только в одном streamе и будут устанавливать значение для его streamа, все остальные streamи будут иметь это значение неинициализированным)

Просто чтобы добавить, 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 } } 

Это объясняет это . Резюме: const должен быть инициализирован во время объявления, readonly может быть инициализирован конструктором (и, следовательно, имеет другое значение в зависимости от используемого конструктора).

РЕДАКТИРОВАНО: см. Выше полученную Gishu для тонкой разницы

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; } 

Член readonly подобен константе в том, что он представляет неизменное значение. Разница в том, что член readonly может быть инициализирован во время выполнения, в конструкторе, а также может быть инициализирован по мере их объявления.

 public class MyClass1 { public readonly double PI2 = 3.14159; //or public readonly double PI3; public MyClass2() { PI3 = 3.14159; } } 

Const

  • Они не могут быть объявлены как static (они неявно статичны)
  • Значение константы оценивается во время компиляции
  • константы инициализируются только при объявлении

только для чтения

  • Они могут быть либо на уровне экземпляра, либо на статическом
  • Значение оценивается во время выполнения
  • readonly может быть инициализирован в декларации или кодом в конструкторе

Константа const является константой времени компиляции, тогда как readonly позволяет вычислять значение во время выполнения и устанавливать в конструкторе или инициализаторе поля. Таким образом, константа const всегда постоянна, но «readonly» доступен только для чтения после ее назначения.

Эрик Липперт из команды C # имеет больше информации о разных типах неизменяемости

Вот еще одна ссылка, демонстрирующая, как const не является безопасным версией или релевантным для ссылочных типов.

Резюме :

  • Значение вашего свойства const устанавливается во время компиляции и не может меняться во время выполнения
  • Константа не может быть помечена как статическая – ключевое слово обозначает, что они являются статическими, в отличие от полей readonly, которые могут.
  • Const не может быть ничего, кроме значений (примитивных) типов
  • Ключевое слово readonly помечает поле как неизменяемое. Однако свойство может быть изменено внутри конструктора classа
  • Ключевое слово только для чтения можно также комбинировать со статикой, чтобы заставить его действовать так же, как const (по крайней мере на поверхности). Существует заметная разница, когда вы смотрите на IL между двумя
  • константные поля помечены как «буквальные» в IL, а readonly – «initonly»,

Еще одна полученная информация: значения readonly могут быть изменены «коварным» кодом через reflection.

 var fi = this.GetType() .BaseType .GetField("_someField", BindingFlags.Instance | BindingFlags.NonPublic); fi.SetValue(this, 1); 

Могу ли я изменить частное поле, наследуемое только на чтение в C #, используя reflection?

Только чтение : значение может быть изменено через Ctor во время выполнения. Но не через функцию-член

Константа : по умолчанию статична. Значение не может быть изменено нигде (Ctor, Function, runtime etc no-where)

Я считаю, что значение const одинаково для всех объектов (и должно быть инициализировано литеральным выражением), тогда как readonly может быть различным для каждого экземпляра …

Один из членов команды в нашем офисе предоставил следующие рекомендации о том, когда использовать const, static и readonly:

  • Используйте const, когда у вас есть переменная типа, которую вы можете знать во время выполнения (строковый литерал, int, double, enums, …), который вы хотите, чтобы все экземпляры или пользователи classа имели доступ к тому, где значение не должно меняться.
  • Используйте static, когда у вас есть данные, которые вы хотите, чтобы все экземпляры или пользователи classа имели доступ к тому, где значение может измениться.
  • Используйте static readonly, когда у вас есть переменная типа, которую вы не можете знать во время выполнения (объекты), в которой вы хотите, чтобы все экземпляры или пользователи classа имели доступ к тому, где значение не должно меняться.
  • Используйте 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; } } } 

Переменные, отмеченные как const, представляют собой немного больше, чем строго типизированные macros #define, при компиляции ссылки на переменные const заменяются встроенными значениями литерального выражения. Таким образом, можно использовать только определенные встроенные примитивные типы значений. Переменные, помеченные как readonly, могут быть заданы в конструкторе во время выполнения, а их постоянная доступность также применяется во время выполнения. Существует несколько незначительных эксплуатационных расходов, связанных с этим, но это означает, что вы можете использовать readonly с любыми типами (даже ссылочными типами).

Кроме того, константные переменные по своей сути являются статическими, тогда как переменные readonly могут быть конкретными, если это необходимо.

Ключевое слово readonly отличается от ключевого слова const. Поле const может быть инициализировано только при объявлении поля. Поле readonly может быть инициализировано либо в объявлении, либо в конструкторе. Поэтому поля readonly могут иметь разные значения в зависимости от используемого конструктора. Кроме того, хотя константное поле является константой времени компиляции, поле readonly может использоваться для констант времени выполнения, как в следующем примере:

 public static readonly uint l1 = (uint) DateTime.Now.Ticks; 

Ключевое слово readonly отличается от ключевого слова const . Поле const может быть инициализировано только при объявлении поля. Поле readonly может быть инициализировано либо в объявлении, либо в конструкторе . Поэтому поля readonly могут иметь разные значения в зависимости от используемого конструктора. Кроме того, хотя константное поле является константой времени компиляции , поле readonly может использоваться для констант времени выполнения, как в следующем примере:

 public static readonly uint timeStamp = (uint)DateTime.Now.Ticks; 

Еще есть.

Поскольку const действительно работает только с базовыми типами данных, если вы хотите работать с classом, вы можете почувствовать «принудительное» использование ReadOnly. Однако остерегайтесь ловушки! ReadOnly означает, что вы не можете заменить объект другим объектом (вы не можете заставить его ссылаться на другой объект). Но любой процесс, который имеет ссылку на объект, может свободно изменять значения внутри объекта!

Поэтому не следует путать, думая, что ReadOnly подразумевает, что пользователь не может ничего изменить. В C # нет простого синтаксиса, чтобы предотвратить изменение экземпляра classа из-за изменения его внутренних значений (насколько я знаю).

Существует заметная разница между полями const и readonly в C # .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 может быть объявлен как статический, но необязательный. Не нужно инициализировать во время объявления. Его значение может быть назначено или изменено с помощью конструктора. Таким образом, он дает преимущество при использовании в качестве члена classа экземпляра. Два разных экземпляра могут иметь другое значение поля readonly. Для экс-

 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.

Константа будет скомпилирована в потребитель в качестве литерального значения, тогда как статическая строка будет служить ссылкой на определенное значение.

В качестве упражнения попробуйте создать внешнюю библиотеку и использовать ее в консольном приложении, затем измените значения в библиотеке и перекомпилируйте ее (без перекомпиляции потребительской программы), отбросьте DLL в каталог и запустите EXE вручную, вы должны найти что постоянная строка не изменяется.

постоянная

Мы должны указать значение в поле const, когда оно определено. Затем компилятор сохраняет значение константы в метаданных сборки. Это означает, что константа может быть определена только для примитивного типа, такого как boolean, char, byte и т. Д. Константы всегда считаются статическими членами, а не членами экземпляра.

Readonly

Поля Readonly могут быть разрешены только во время выполнения. Это означает, что мы можем определить значение для значения, используя конструктор для типа, в котором объявлено поле. Проверка выполняется компилятором, что поля readonly не записываются каким-либо другим способом, кроме конструктора.

Подробнее об обоих объясненных здесь в этой статье

В принципе; вы можете присвоить значение статическому полю readonly неизменному значению во время выполнения, тогда как константе должно быть присвоено постоянное значение.

const должна быть жестко закодирована , где, поскольку readonly может быть задано в конструкторе classа.

Const и readonly похожи, но они не совсем то же самое. Поле const является константой времени компиляции, что означает, что это значение может быть вычислено во время компиляции. Поле readonly позволяет создавать дополнительные сценарии, в которых некоторый код должен выполняться во время построения типа. После построения поле readonly не может быть изменено.

Например, члены константы могут использоваться для определения таких членов, как:

 struct Test { public const double Pi = 3.14; public const int Zero = 0; } 

так как значения, такие как 3.14 и 0, являются константами времени компиляции. Однако рассмотрите случай, когда вы определяете тип и хотите предоставить некоторые предварительные экземпляры. Например, вы можете определить class «Цвет» и предоставить «константы» для обычных цветов, таких как «Черный», «Белый» и т. Д. Это невозможно сделать с помощью константных членов, поскольку правые части не являются константами времени компиляции. Это можно сделать с помощью обычных статических элементов:

 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; } } 

но тогда нет ничего, что могло бы заставить клиента «Цвет» уклониться от него, возможно, заменив значения «черный и белый». Излишне говорить, что это вызовет ужас для других клиентов classа 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(AC); } } 

Теперь, может ли генерируемый код полагаться на то, что AC является константой времени компиляции? Т.е., может ли использование переменного тока просто заменить на значение 0? Если вы говорите «да», то это означает, что разработчик A не может изменить способ инициализации AC – это связывает руки разработчика A без разрешения. Если вы скажете «нет» на этот вопрос, тогда будет пропущена важная оптимизация. Возможно, автор A положителен, что AC всегда будет равен нулю. Использование как const, так и readonly позволяет разработчику A указать намерение. Это улучшает поведение версий, а также повышает производительность.

ReadOnly: значение будет инициализировано только один раз из конструктора classа.
const: может быть инициализирована в любой функции, но только один раз

Разница в том, что значение статического поля readonly устанавливается во время выполнения, поэтому оно может иметь другое значение для разных исполнений программы. Однако значение константного поля задается постоянной времени компиляции.

Помните: для ссылочных типов в обоих случаях (статический и экземпляр) модификатор readonly только запрещает вам назначать новую ссылку на поле. Он специально не делает неизменным объект, на который указывает ссылка.

Для получения дополнительной информации см. Часто задаваемые вопросы C # по этой теме: http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx

Константные переменные объявляются и инициализируются во время компиляции. Значение не может быть изменено после опекунов. Переменные только для чтения будут инициализированы только из конструктора Static classа. Только чтение используется только тогда, когда мы хотим присвоить значение во время выполнения.

Поле const может быть инициализировано только при объявлении поля. Поле readonly может быть инициализировано либо в объявлении, либо в конструкторе.

Одно можно добавить к тому, что люди сказали выше. Если у вас есть assembly, содержащая значение readonly (например, только для чтения MaxFooCount = 4;), вы можете изменить значение, которое вызывает вызовы сборок, отправив новую версию этой сборки с другим значением (например, только для чтения MaxFooCount = 5;)

Но с константой он будет складываться в код вызывающего абонента, когда собеседник был скомпилирован.

Если вы достигли уровня владения C #, вы готовы к книге Билла Вагнера «Эффективный C #: 50 конкретных способов улучшить ваш C #». Ответы на этот вопрос подробно (и еще 49 вещей).

  • c #: Как использовать перечисление для хранения строковых констант?
  • Как установить переменные в сценариях HIVE
  • C ++ где инициализировать статический const
  • Где постоянные переменные хранятся в C?
  • Как я могу получить все константы типа путем отражения?
  • Как я могу получить содержимое ресурса из статического контекста?
  • Каков наилучший способ реализации констант в Java?
  • Статический readonly vs const
  • В чем разница между char s и char * s?
  • Ruby on Rails: Где определить глобальные константы?
  • Пул строк и постоянный пул
  • Давайте будем гением компьютера.