В чем разница между const
и readonly
в C #?
Когда бы вы использовали один поверх другого?
В чем разница между const
и readonly
в C #?
Когда бы вы использовали один поверх другого?
Ответы:
Помимо очевидного различия
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
значения это похоже на поиск-замену, значение 2 «запекается» в AssemblyB
IL. Это означает, что если завтра я обновлю I_CONST_VALUE
до 20 в будущем. AssemblyB
будет еще 2, пока я не перекомпилирую .readonly
значения это похоже ref
на ячейку памяти. Значение не запекается вAssemblyB
IL. Это означает, что если ячейка памяти обновляется, AssemblyB
получает новое значение без перекомпиляции. Так что, если I_RO_VALUE
обновление до 30, вам нужно только построить AssemblyA
. Все клиенты не должны быть перекомпилированы.Поэтому, если вы уверены, что значение константы не изменится, используйте a const
.
public const int CM_IN_A_METER = 100;
Но если у вас есть константа, которая может измениться (например, точность) или, если вы сомневаетесь, используйте readonly
.
public readonly float PI = 3.14;
Обновление: Аку нужно получить упоминание, потому что он указал это первым. Также мне нужно подключить, где я это узнал .. Эффективный C # - Билл Вагнер
static
Точка , кажется, самый важный и полезный пункт -consts are implicitly static
readonly
переменные могут быть изменены вне конструктора (отражение). Только компилятор пытается помешать вам изменить переменную вне конструктора.
readonly
Переменные @ mini-me не могут быть изменены после завершения конструктора, даже через отражение. Время выполнения не обеспечивает этого. Время выполнения также не означает, что вы не измените string.Empty
его "Hello, world!"
, но я все равно не буду утверждать, что это делает string.Empty
модифицируемым, или что код не должен предполагать, что string.Empty
это всегда будет строка нулевой длины.
Есть гоча с минусами! Если вы ссылаетесь на константу из другой сборки, ее значение будет скомпилировано прямо в вызывающую сборку. Таким образом, когда вы обновите константу в ссылочной сборке, она не изменится в вызывающей сборке!
Чтобы добавить, 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. Поле только для чтения может быть установлено несколько раз в конструкторе (ах). Даже если значение задано в двух разных цепочечных конструкторах, оно все равно разрешено.
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
(они неявно статичны)только для чтения
static const int i = 0;
const
объявления не могут быть сделаны внутри методов?
Const - это константа времени компиляции, тогда как readonly позволяет вычислять значение во время выполнения и устанавливать его в конструкторе или инициализаторе поля. Таким образом, «const» всегда постоянен, но «только для чтения» доступен только для чтения после его назначения.
Эрик Липперт из команды C # имеет больше информации о различных типах неизменяемости
Вот еще одна ссылка, демонстрирующая, как const не является версией, безопасной или релевантной для ссылочных типов.
Резюме :
Только чтение : значение может быть изменено через Ctor во время выполнения. Но не через функцию члена
Постоянная : по умолчанию статическая. Значение не может быть изменено из любого места (Ctor, Function, время выполнения и т. Д. Без указания места)
Еще одно замечание: значения, доступные только для чтения, могут быть изменены «хитрым» кодом с помощью отражения.
var fi = this.GetType()
.BaseType
.GetField("_someField",
BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, 1);
Могу ли я изменить частное унаследованное поле только для чтения в C #, используя отражение?
Я считаю, что const
значение является одинаковым для всех объектов (и должно быть инициализировано литеральным выражением), тогда как readonly
может быть разным для каждого экземпляра ...
Один из членов команды в нашем офисе предоставил следующие рекомендации о том, когда использовать const, static и readonly:
И последнее замечание: поле 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; }
}
}
когда использовать const
илиreadonly
const
readonly
App.config
, но после инициализации ее нельзя изменитьПеременные, помеченные как const, немного больше, чем строго типизированные макросы #define, во время компиляции ссылки на переменные const заменяются встроенными литеральными значениями. Как следствие, таким образом могут использоваться только определенные встроенные типы примитивных значений. Переменные, помеченные как доступные только для чтения, могут быть установлены в конструкторе во время выполнения, и их доступность только для чтения обеспечивается во время выполнения. Это связано с незначительными затратами на производительность, но это означает, что вы можете использовать readonly с любым типом (даже ссылочными).
Кроме того, константные переменные по своей природе являются статическими, тогда как переменные только для чтения могут быть специфичными для экземпляра, если это необходимо.
Еще одна ошибка .
Поскольку const действительно работает только с базовыми типами данных, если вы хотите работать с классом, вы можете почувствовать себя «вынужденными» использовать ReadOnly. Однако остерегайтесь ловушки! ReadOnly означает, что вы не можете заменить объект другим объектом (вы не можете заставить его ссылаться на другой объект). Но любой процесс, имеющий ссылку на объект, может свободно изменять значения внутри объекта!
Так что не думайте, что ReadOnly подразумевает, что пользователь не может ничего изменить. В C # нет простого синтаксиса, который бы препятствовал изменению внутренних значений экземпляра класса (насколько я знаю).
Существует заметная разница между полями 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.
Константа будет скомпилирована в потребителя как буквальное значение, в то время как статическая строка будет служить ссылкой на определенное значение.
В качестве упражнения попробуйте создать внешнюю библиотеку и использовать ее в консольном приложении, затем измените значения в библиотеке и перекомпилируйте ее (без перекомпиляции программы-потребителя), поместите DLL в каталог и запустите EXE вручную, вы должны найти что постоянная строка не меняется.
постоянная
Нам нужно предоставить значение в поле const, когда оно определено. Затем компилятор сохраняет значение константы в метаданных сборки. Это означает, что константа может быть определена только для примитивного типа, такого как логическое значение, символ, байт и так далее. Константы всегда считаются статическими членами, а не членами экземпляра.
Readonly
Поля только для чтения могут быть разрешены только во время выполнения. Это означает, что мы можем определить значение для значения, используя конструктор для типа, в котором объявлено поле. Проверка выполняется компилятором, что поля только для чтения не записываются никаким методом, кроме конструктора.
Подробнее об обоих объяснено здесь в этой статье
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 указать намерение. Это улучшает поведение при управлении версиями, а также повышает производительность.
Разница заключается в том, что значение статического поля только для чтения устанавливается во время выполнения, поэтому оно может иметь различное значение для разных исполнений программы. Тем не менее, значение поля const устанавливается на постоянную времени компиляции.
Помните: для ссылочных типов в обоих случаях (статических и экземпляровых) модификатор readonly только запрещает вам назначать новую ссылку на поле. Это определенно не делает неизменным объект, на который указывает ссылка.
Для получения подробной информации, пожалуйста, обратитесь к разделу Часто задаваемые вопросы по этой теме на C #: http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx
Постоянные переменные объявляются и инициализируются во время компиляции. Значение не может быть изменено после опеки. Переменные только для чтения будут инициализированы только из статического конструктора класса. Только чтение используется только тогда, когда мы хотим присвоить значение во время выполнения.
Const : Абсолютное постоянное значение в течение срока службы приложения.
Только для чтения : это может быть изменено во время выполнения.
Одна вещь, чтобы добавить к тому, что люди сказали выше. Если у вас есть сборка, содержащая значение только для чтения (например, readonly MaxFooCount = 4;), вы можете изменить значение, которое видят вызывающие сборки, отправив новую версию этой сборки с другим значением (например, только для чтения MaxFooCount = 5;)
Но с помощью const он будет свернут в код вызывающего, когда он будет скомпилирован.
Если вы достигли этого уровня владения C #, вы готовы к книге Билла Вагнера «Эффективное C #: 50 конкретных способов улучшить ваш C #», которая подробно отвечает на этот вопрос (и 49 других вещей).