В чем разница между const и readonly? - PullRequest
1178 голосов
/ 11 сентября 2008

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

Ответы [ 32 ]

1136 голосов
/ 11 сентября 2008

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

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

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

public const int CM_IN_A_METER = 100;

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

public readonly float PI = 3.14;

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

257 голосов
/ 11 сентября 2008

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

144 голосов
/ 02 декабря 2008

Константы

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

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

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

Статические поля только для чтения

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

Чтобы добавить, 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
  }
}
37 голосов
/ 11 сентября 2008

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

РЕДАКТИРОВАТЬ: см. Гишу Гишу выше для тонкой разницы

29 голосов
/ 21 мая 2011

const: Нигде не может быть изменено.

readonly: Это значение можно изменить только в конструкторе. Нельзя изменить в обычных функциях.

24 голосов
/ 20 октября 2008

Есть маленькая ошибка с 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
    }
}
22 голосов
/ 17 сентября 2012

Постоянный член определяется во время компиляции и не может быть изменен во время выполнения. Константы объявляются как поле с использованием ключевого слова 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;
     }
}

сопзЬ

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

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

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

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

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

15 голосов
/ 31 января 2009

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

Основная информация

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