В чем разница между const и readonly в C #?

В чем разница между constи readonlyв C #?

Когда бы вы использовали один поверх другого?

11.09.2008 08:02:19
Мне пришлось посмотреть несколько ответов, чтобы найти эту ссылку, но она хорошая. Взгляд Эрика Липперта на неизменность в C #
Frank Bryce 17.12.2015 16:06:02
@donstack, фактически в соответствии со ссылкой на C # , поле только для чтения может быть назначено и переназначено несколько раз в пределах объявления поля и конструктора.
Marques 23.10.2019 16:45:34
Несмотря на то, что склонен к этому, теперь кажется, что больше не нужно больше
IceFire 4.04.2020 07:19:27
30 ОТВЕТОВ
РЕШЕНИЕ

Помимо очевидного различия

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

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

public const int CM_IN_A_METER = 100;

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

public readonly float PI = 3.14;

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

1279
22.09.2015 08:01:23
staticТочка , кажется, самый важный и полезный пункт -consts are implicitly static
LCJ 21.01.2013 14:00:51
Часть о ссылочных значениях является наиболее важной. Значения констант могут быть оптимизированы.
CodingBarfield 5.06.2013 07:03:30
readonlyпеременные могут быть изменены вне конструктора (отражение). Только компилятор пытается помешать вам изменить переменную вне конструктора.
Bitterblue 5.06.2013 14:10:34
readonlyПеременные @ mini-me не могут быть изменены после завершения конструктора, даже через отражение. Время выполнения не обеспечивает этого. Время выполнения также не означает, что вы не измените string.Emptyего "Hello, world!", но я все равно не буду утверждать, что это делает string.Emptyмодифицируемым, или что код не должен предполагать, что string.Emptyэто всегда будет строка нулевой длины.
user743382 14.04.2014 11:55:40
blogs.msmvps.com/jonskeet/2014/07/16/… интересна только для чтения накладные расходы только на чтение
CAD bloke 5.08.2014 21:52:55

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

6
11.09.2008 08:03:46

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

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

40
11.09.2008 09:52:22

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

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

21
11.09.2008 08:07:46

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

273
10.04.2014 15:53:37
При декомпиляции (Reflector, ILSpy, ..) на константу НИКОГДА НИКОГДА не ссылается ни один, независимо от того, какая сборка или другая сборка, поэтому вы вообще не можете анализировать использование константы в скомпилированном коде.
springy76 19.08.2016 13:02:01

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

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

4
5.01.2009 22:34:33
Добавил, что в константах строго прописаны макросы #define. В противном случае мы можем отпугнуть всех людей на C или C ++. :-)
Jason Baker 5.01.2009 22:35:21

Чтобы добавить, 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
  }
}
58
29.09.2008 21:19:13
Есть ли другой ссылочный тип, stringкоторый вы не могли бы использовать в качестве константы?
springy76 19.08.2016 13:02:57
Вы можете иметь constсо ссылочными типами, отличными от строки, но константа может иметь только значение null.
Mike Rosoft 27.04.2018 14:28:40

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

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

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

0
15.09.2008 10:14:17

Ключевым отличием является то, что Const является эквивалентом C #DEFINE. Число буквально подставляется а-ля прекомпилятором. Readonly на самом деле рассматривается как переменная.

Это различие особенно актуально, когда у вас есть проект А в зависимости от публичной константы из проекта Б. Предположим, что публичная константа изменяется. Теперь ваш выбор const / readonly повлияет на поведение в проекте A:

Const: проект A не перехватывает новое значение (конечно, если оно не перекомпилировано с новым const), потому что оно было скомпилировано с подставленными константами.

ReadOnly: проект A всегда будет запрашивать значение переменной для проекта B, поэтому он получит новое значение публичной константы в B.

Честно говоря, я бы порекомендовал вам использовать readonly практически для всего, кроме действительно универсальных констант (например, Pi, Inches_To_Centimeters). Для всего, что может измениться, я использую readonly.

Надеюсь, это поможет, Алан.

0
15.09.2008 21:30:19

Они оба постоянны, но const доступен также во время компиляции. Это означает, что одним из отличий является то, что вы можете использовать переменные const в качестве входных данных для конструкторов атрибутов, но не для переменных только для чтения.

Пример:

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; }
  }
}
5
7.01.2016 23:44:00

Еще одна ошибка .

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

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

3
17.09.2008 13:28:01
Да, это больше общая тема. Если у вас есть свойство get only, открывающее доступ к массиву, вы все равно можете изменить его. Вы не можете установить другой arraylist для этого свойства, но вы не можете запретить пользователю изменять arraylist.
Gishu 17.09.2008 13:31:27

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

  • Используйте const, когда у вас есть переменная типа, который вы можете знать во время выполнения (string literal, int, double, enums, ...), что вы хотите, чтобы все экземпляры или потребители класса имели доступ к тому месту, где значение не должно изменяться.
  • Используйте static, когда у вас есть данные, к которым у всех экземпляров или потребителей класса есть доступ, где значение может измениться.
  • Используйте статическое чтение только тогда, когда у вас есть переменная типа, который вы не можете знать во время выполнения (объекты), что вы хотите, чтобы все экземпляры или потребители класса имели доступ к тому месту, где значение не должно изменяться.
  • Используйте readonly, когда у вас есть переменная уровня экземпляра, которую вы будете знать во время создания объекта, которая не должна изменяться.

И последнее замечание: поле const является статическим, но обратное неверно.

5
2.10.2008 20:43:37
Я думаю, что вы имеете в виду "говорить". Обратное было бы «неконстантное поле не является статическим». Что может или не может быть правдой. И наоборот, «статическое поле (всегда) const» не соответствует действительности.
Michael Blackburn 27.04.2016 21:02:23

Есть маленькая ошибка с 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
    }
}
26
19.10.2008 22:14:57

Константы

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

Только для чтения полей

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

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

  • Оцениваются, когда выполнение кода достигает ссылки на класс (когда создается новый экземпляр или выполняется статический метод)
  • Должно иметь оценочное значение к моменту создания статического конструктора
  • Не рекомендуется помещать ThreadStaticAttribute в них (статические конструкторы будут выполняться только в одном потоке и будут устанавливать значение для его потока; все остальные потоки будут иметь это значение неинициализированным)
157
9.06.2011 12:03:30

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

Резюме :

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

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

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

2
8.09.2009 12:52:20
Я искренне сомневаюсь, что это правда ... Я пойду проверю.
ljs 8.09.2009 12:23:53
это один из 50 конкретных способов улучшить ваш C # - amazon.co.uk/Effective-Specific-Ways-Improve-Your/dp/0321245660/…
Russ Cam 8.09.2009 12:24:56
Russ Cam 8.09.2009 12:27:32
@ Андрей Харе - да, я только что проверил. Я очень удивлен, это настоящая ошибка, я действительно очень удивлен этим, поражен, что это так ...!
ljs 8.09.2009 12:29:18
Я, однако, возражаю против использования здесь указателя слова. Это не указатель, это ссылка, и есть разница в C # , как вы можете манипулировать неуправляемые указатели в небезопасном режиме , поэтому очень важно , чтобы различать между ними.
ljs 8.09.2009 12:31:23

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

1
8.09.2009 12:24:24

Еще одно замечание: значения, доступные только для чтения, могут быть изменены «коварным» кодом посредством отражения.

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

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

9
23.05.2017 11:54:59

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

3
20.02.2011 12:29:26

const: Нельзя нигде изменить.

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

32
27.11.2013 22:04:55

Постоянный член определяется во время компиляции и не может быть изменен во время выполнения. Константы объявляются как поле с использованием 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 может быть инициализирован в объявлении или кодом в конструкторе
26
27.04.2016 23:05:21
Они не могут быть статичными , они статичны. Вы должны дать понять, если вы имели в виду, что никто не может объявитьstatic const int i = 0;
nawfal 13.12.2013 20:21:44
Можете ли вы объяснить, почему constобъявления не могут быть сделаны внутри методов?
Minh Tran 29.10.2017 17:38:16

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

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

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

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

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 с этим взломать, возможно, путем замены значений Black и White. Излишне говорить, что это вызвало бы смятение у других клиентов класса 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;
    }
}

Интересно отметить, что члены-константы всегда являются статическими, тогда как член только для чтения может быть статическим или нет, как обычное поле.

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

public class A
{
    public static const C = 0;
}

и другой разработчик написал код, который опирался на A:

public class B
{
    static void Main() {
        Console.WriteLine(A.C);
    }
}

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

1
28.09.2013 08:19:52

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

1
24.01.2014 07:34:17

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

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

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

1
5.04.2014 14:39:18

Существует заметная разница между полями const и readonly в C # .Net

const по умолчанию является статическим и должен быть инициализирован постоянным значением, которое не может быть изменено позже. Изменение значения также не допускается в конструкторах. Его нельзя использовать со всеми типами данных. Для экс-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 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.

3
15.12.2014 13:01:10

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

1
9.04.2015 21:09:25

постоянная

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

Readonly

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

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

2
4.08.2015 05:34:27

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

Постоянная : по умолчанию статическая. Значение не может быть изменено из любого места (Ctor, Function, время выполнения и т. Д. Без указания места)

11
12.01.2016 17:42:57
спасибо, что не заставили меня прочитать 4 параграфа только за эти два выноса ...
Don Cheadle 26.02.2018 19:11:06

ПОСТ

  1. Ключевое слово const может применяться к полям или локальным переменным
  2. Мы должны назначить поле const во время объявления
  3. Память не выделена, поскольку значение const встраивается в сам код IL после компиляции. Это все равно, что найти все вхождения переменной const и заменить ее значением. Таким образом, код IL после компиляции будет иметь жестко запрограммированные значения вместо константных переменных.
  4. Const в C # по умолчанию являются статическими.
  5. Значение является постоянным для всех объектов
  6. Существует проблема с версионированием dll - это означает, что всякий раз, когда мы изменяем открытую переменную или свойство const (фактически, это не предполагается изменять теоретически), любая другая dll или сборка, которая использует эту переменную, должна быть пересобрана
  7. Только встроенные типы C # могут быть объявлены как константы
  8. Поле const не может быть передано как параметр ref или out

ReadOnly

  1. Ключевое слово readonly применяется только к полям, а не к локальным переменным
  2. Мы можем назначить поле только для чтения во время объявления или в конструкторе, а не в каких-либо других методах.
  3. динамическая память выделена для полей только для чтения, и мы можем получить значение во время выполнения.
  4. Readonly принадлежит объекту, созданному таким образом, к которому можно получить доступ только через экземпляр класса. Чтобы сделать его членом класса, мы должны добавить статическое ключевое слово перед чтением.
  5. Значение может отличаться в зависимости от используемого конструктора (так как оно принадлежит объекту класса)
  6. Если вы объявляете не примитивные типы (ссылочный тип) только для чтения, ссылка является неизменной, а не объектом, который она содержит.
  7. Так как значение получается во время выполнения, нет проблем с версиями dll для полей / свойств только для чтения.
  8. Мы можем передать поле только для чтения в качестве параметров ref или out в контексте конструктора.
4
8.09.2018 06:55:48

Проще говоря, Const - это время компиляции, а readonly - это время выполнения.

0
17.01.2019 16:27:57