Вопрос

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

Это было полезно?

Решение

Помимо кажущейся разницы

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

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

public const int CM_IN_A_METER = 100;

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

public readonly float PI = 3.14;

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

Другие советы

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

Константы

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

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

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

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

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

Добавлю: 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:Это значение можно изменить только в конструкторе.Невозможно изменить в обычных функциях.

Есть небольшая ошибка с 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;
     }
}

константа

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

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

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

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

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

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

Краткое содержание:

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

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

Постоянный :По умолчанию статический.Значение нельзя изменить ниоткуда (Ctor, Function, runtime и т. д. нигде)

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

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

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

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

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

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

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

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

Пример:

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 действительно работает только с базовыми типами данных, если вы хотите работать с классом, вы можете почувствовать себя «вынужденным» использовать 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;
    }
}

Затем поле только для чтения можно инициализировать мгновенными конкретными значениями следующим образом:

A objOne = new A(5);
A objTwo = new A(10);

Здесь экземпляр objOne будет иметь значение поля readonly 5, а objTwo — 10.Что невозможно с использованием const.

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

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

Постоянный

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

Только чтение

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

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

КОНСТ

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

Только чтение

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

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

А 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 является константой времени компиляции?То есть можно ли просто заменить использование переменного тока значением 0?Если вы скажете на это «да», то это означает, что разработчик A не может изменить способ инициализации AC — это связывает руки разработчику A без разрешения.Если вы ответите «нет» на этот вопрос, то вы упустите важную оптимизацию.Возможно, автор A уверен, что A.C всегда будет равен нулю.Использование как const, так и readonly позволяет разработчику A указать намерение.Это обеспечивает лучшее поведение при управлении версиями, а также лучшую производительность.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top