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


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

30 1035

30 ответов:

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

  • необходимо объявить значение во время определения для const VS readonly значения могут быть вычислены динамически, но должны быть назначены до завершения работы конструктора.. после этого его замораживают.
  • 'const неявно 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 - 'в' 'ы Ил. Это означает, что если завтра я буду обновлять I_CONST_VALUE до 20 в будущем. AssemblyB все равно будет 2, пока я не перекомпилирую его.
  • в случае readonly значение, это как ref в ячейку памяти. Значение не запекается в AssemblyB'ы Ил. Это означает, что если ячейка памяти обновляется,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;

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

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

константы

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

только для чтения полей экземпляра

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

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

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

просто чтобы добавить, ReadOnly для ссылочных типов только делает ссылку 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 может быть инициализирован на конструкторе (и, таким образом, иметь другое значение в зависимости от используемого конструктора).

редактировать: см. попался Гишу выше на тонкую разницу

const: не может быть изменен в любом месте.

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

есть небольшой gotcha с 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 (они неявно статические)
  • значение константы вычисляется во время компиляции
  • константы инициализируются только при объявлении

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

  • они могут быть или на уровне экземпляра или статический!--16-->
  • значение вычисляется во время выполнения
  • только для чтения может инициализируется в объявлении или кодом в конструкторе

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

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

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

резюме:

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

еще один gotcha: readonly значения могут быть изменены "окольным" кодом через отражение.

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

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

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

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

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

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

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

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

они оба постоянны, но 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, немного больше, чем строго типизированные макросы #define, во время компиляции ссылки на переменные const заменяются встроенными литеральными значениями. Как следствие, таким образом можно использовать только некоторые встроенные примитивные типы значений. Переменные, помеченные только для чтения, могут быть установлены в конструкторе во время выполнения, и их доступность только для чтения также применяется во время выполнения. Есть некоторые незначительные затраты на производительность, связанные с этим, но это означает, что вы можете использовать только чтение с любым типом (даже ссылочный тип.)

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

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

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

на только для чтения ключевое слово отличается от const ключевое слово. А const поле может быть инициализировано только в декларация поля. А только для чтения поле может быть инициализировано либо в декларация или конструктор. Таким образом, только для чтения поля могут иметь разные значения в зависимости от используемого конструктора. Кроме того, в то время как const поле-это времени компиляции константа,только для чтения поле может быть использовано для runtime константы, как в следующем примере:

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

другое понял.

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

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

существует заметная разница между полями 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 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 не записываются никаким другим методом, кроме конструктора.

подробнее о объяснил вот в этой статье

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

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

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

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

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

так как значения типа 3.14 и 0 являются временем компиляции константы. Однако рассмотрим случай, когда вы определяете тип и хотите предоставить некоторые его экземпляры pre-fab. Например, вы можете определить класс цвета и предоставить "константы" для общих цветов, таких как черный, белый и т. д. Это невозможно сделать с членами const, так как правые стороны не являются константами времени компиляции. Это можно сделать с помощью обычных статических членов:

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. Функция "только для чтения" обращается к этому сценарию. Просто вводя ключевое слово 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 всегда статичны, тогда как член только для чтения может быть либо статическим, либо нет, как и обычный поле.

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

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

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

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

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

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

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

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

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

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

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

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

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

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