Есть ли разница между закрытыми константными и закрытыми переменными только для чтения в C #? - PullRequest
30 голосов
/ 04 января 2009

Есть ли разница между наличием переменной private const или переменной private static readonly в C # (кроме необходимости присваивать const выражение времени компиляции)?

Поскольку они оба являются частными, связь с другими библиотеками отсутствует. Так будет ли это иметь значение? Может ли это повлиять на производительность, например? Стажированные строки? Что-нибудь похожее?

Ответы [ 9 ]

33 голосов
/ 04 января 2009

Ну, вы можете использовать константы в атрибутах, так как они существуют во время компиляции. Вы не можете предсказать значение статической переменной только для чтения, поскольку .cctor может инициализировать его из конфигурации и т. Д.

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

Повторная стажировка; хотя вы можете сделать это вручную, чаще всего это литеральная функция компилятора / среды выполнения; если вы инициируете поле только для чтения через литерал:

someField = "abc";

, тогда "abc" будет интернирован. Если вы прочитаете это из конфигурации, это не будет. Поскольку константная строка должна быть литералом, она также будет интернирована, но к ней обращаются по-разному: опять же, чтение из поля - это обратная ссылка, а не ldstr.

11 голосов
/ 04 января 2009

Действительно, два типа не могут быть изменены после их инициализации, но между ними есть некоторые различия:

  • 'const' должен быть инициализирован там, где они объявлены (во время компиляции), тогда как 'readonly' может быть инициализирован там, где он объявлен или внутри конструктора (ar runtime).

Например, const может использоваться в этой ситуации:

public class MathValues
{
  public const double PI = 3.14159;
}

И readonly будет лучше для этого случая:

public class Person
{
    public readonly DateTime birthDate;

    public Person(DateTime birthDate)
    {
        this.birthDate = birthDate;
    }
}

или

public class Person
{
    public readonly DateTime birthDate = new DateTime(1986, 1, 24);
}
  • 'const' является статическим, поэтому он используется всеми экземплярами этого класса и доступен напрямую (например, MathValues.PI), тогда как readonly не является статическим. Как следствие, объявление типа «static const» недопустимо, поскольку const является статическим, но «static readonly» допустимо

  • 'const' может содержать только целочисленный тип (sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool или string), перечисление или ссылка на null (не на классы или структуры, потому что они инициализируются во время выполнения с ключевым словом «new»), тогда как «readonly» может содержать сложные типы, структуры или классы (используя ключевое слово new при инициализации), но не может содержать перечисления

5 голосов
/ 04 января 2009

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

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

4 голосов
/ 04 января 2009

Вот различия между C # .NET const , readonly и static readonly полей (из этой статьи ).

Константы

  • Статический по умолчанию
  • Должно иметь значение времени компиляции (т.е. вы можете иметь "A" + "B", но не можете иметь вызовы методов)
  • Может использоваться в атрибутах
  • Копируются в каждую сборку, которая их использует (каждая сборка получает локальную копию значений)
  • Может быть объявлено в функциях

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

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

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

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

Существует заметная разница между const и полями только для чтения в 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 будет иметь значение поля только для чтения, равное 5, а objTwo - 10. Что невозможно при использовании const.

2 голосов
/ 16 апреля 2009

Еще одна вещь. Я не видел этого в комментариях выше, хотя, возможно, я пропустил это. Вы не можете создать постоянный массив.

private const int[] values = new int[] { 1, 2, 3 };

Но вы можете создать его, используя статическое поле только для чтения.

private static readonly int[] values = new int[] { 1, 2, 3 };

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

private static readonly int?[] values = new int?[] { null, 1, 2, 3 };

Не можете сделать с константой, не так ли?

2 голосов
/ 04 января 2009

Используется? На самом деле, нет. Констант оцениваются во время компиляции, а readonly - во время выполнения. Вы также можете присвоить переменной только для чтения значение в конструкторе.

1 голос
/ 03 апреля 2009

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

В случае статического чтения только содержащему классу разрешено изменять только его

в объявлении переменной (через инициализатор переменной) в статическом конструкторе (конструкторы экземпляров, если он не статический) static readonly обычно используется, если тип поля не разрешен в объявлении const или когда значение неизвестно во время компиляции.

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

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

class Program

{

  public static readonly Test test = new Test();

  static void Main(string[] args)

  {

     test.Name = "Program";

     test = new Test(); // Error: A static readonly field cannot be assigned to (except in a static constructor or a variable initializer)

  }

}

class Test

{

   public string Name;

}

Различие состоит в том, что статический доступный только для чтения может быть изменен содержащим классом, но const никогда не может быть изменен и должен быть инициализирован как постоянная времени компиляции. Чтобы немного расширить статический случай только для чтения, содержащий его класс может только изменить его:

- в объявлении переменной (через инициализатор переменной).

- в статическом конструкторе (конструкторы экземпляров, если он не является статическим).


Const Keyword в C # .NET

Пример: public const string abc = “xyz”; Инициализируется только при объявлении. Значение оценивается во время компиляции и не может быть изменено во время выполнения. Попытка изменить его приведет к ошибке компиляции. Const уже отчасти статичен. Так как классы и структуры инициализируются во время выполнения с новым ключевым словом, вы не можете установить константу для класса или структуры. Но это должен быть один из целочисленных типов. Ключевое слово только для чтения в C # .NET

Пример: public readonly string abc; Может быть инициализирован в коде объявления или в коде константора. Значение оценивается во время выполнения. Может быть объявлен как статический атрибут или атрибут уровня экземпляра. Поле только для чтения может содержать сложный объект, используя ключевое слово new во время выполнения.

0 голосов
/ 04 января 2009

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

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

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

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

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

...