Статическое чтение только против const - PullRequest
1306 голосов
/ 16 апреля 2009

Я прочитал около const и static readonly полей. У нас есть несколько классов, которые содержат только постоянные значения. Используется для различных вещей в нашей системе. Так что мне интересно, если мои наблюдения верны:

Должны ли такие постоянные значения всегда быть static readonly для всего, что является публичным? И использовать только const для внутренних / защищенных / личных значений?

Что вы рекомендуете? Должен ли я даже не использовать static readonly поля, а использовать свойства, может быть?

Ответы [ 15 ]

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

public static readonly поля немного необычны; public static свойства (только с get) будут более распространенными (возможно, подкрепленными полем private static readonly).

const значения записываются непосредственно в колл-сайт; это обоюдоострый:

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

Если значение никогда никогда не изменится, то с const все в порядке - Zero и т. Д. Делают разумные выводы; p Кроме этого, static свойства более распространены.

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

Я бы использовал static readonly, если Consumer находится в другой сборке. Наличие const и Consumer в двух разных сборках - хороший способ выстрелить себе в ногу .

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

Следует отметить несколько более важных вещей:

const int a

  • должен быть инициализирован.
  • инициализация должна быть в время компиляции .

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

  • может использовать значение по умолчанию без инициализации.
  • инициализация может быть выполнена в время выполнения (Редактировать: только в конструкторе).
162 голосов
/ 11 сентября 2013

Это просто дополнение к другим ответам. Я не буду их повторять (сейчас четыре года спустя).

Существуют ситуации, когда const и неконстантный имеют разные семантики. Например:

const int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

распечатывает True, тогда как:

static readonly int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

пишет False.

Причина в том, что метод x.Equals имеет две перегрузки, одна из которых принимает short (System.Int16), а другая - object (System.Object). Теперь вопрос в том, применим ли один или оба к моему аргументу y.

Когда y является константой времени компиляции (литералом), в случае const становится важным, что существует неявное преобразование из int в short при условии, что int является константой, и при условии, что компилятор C # проверяет, что его значение находится в диапазоне short (то есть 42). См. Неявные преобразования константных выражений в Спецификации языка C #. Таким образом, обе перегрузки должны быть учтены. Перегрузка Equals(short) является предпочтительной (любой short является object, но не все object являются short). Таким образом, y преобразуется в short, и эта перегрузка используется. Затем Equals сравнивает два short одинакового значения, и это дает true.

Когда y не является константой, не существует неявного преобразования из int в short. Это потому, что в общем случае int может быть слишком большим, чтобы поместиться в short. ( явное преобразование существует, но я не сказал Equals((short)y), так что это не имеет значения.) Мы видим, что применяется только одна перегрузка, Equals(object). Итак, y упакован в object. Затем Equals будет сравнивать System.Int16 с System.Int32, и поскольку типы времени выполнения даже не согласуются, это даст false.

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

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

Следует отметить, что const ограничен типами примитивов / значений (исключение составляют строки)

24 голосов
/ 14 ноября 2012

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

Краткая и понятная ссылка на MSDN здесь

21 голосов
/ 12 января 2016

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

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

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

Вы можете посмотреть мое репо: Типы свойств C # .

15 голосов
/ 28 сентября 2013

const и readonly похожи, но они не совсем одинаковы.

Поле const является константой времени компиляции, что означает, что это значение может быть вычислено во время компиляции. Поле readonly включает дополнительные сценарии, в которых некоторый код должен выполняться во время конструирования типа. После построения поле 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, green, blue) = (r, g, b);
}

Но тогда ничто не может помешать клиенту Color изменить его, возможно, путем замены значений черного и белого. Излишне говорить, что это вызвало бы смятение у других клиентов класса 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, green, blue) = (r, g, b);
}

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

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

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

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

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 указать намерение. Это улучшает поведение при управлении версиями и повышает производительность.

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

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

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

7 голосов
/ 09 сентября 2013

Const: Const - это не что иное, как «константа», переменная, значение которой является постоянным, но во время компиляции. И обязательно присвоить ему значение. По умолчанию const является статическим, и мы не можем изменить значение переменной const во всей программе.

Static ReadOnly: Значение переменной типа Static Readonly может быть назначено во время выполнения или назначено во время компиляции и изменено во время выполнения. Но значение этой переменной можно изменить только в статическом конструкторе. И не может быть изменено в дальнейшем. Это может измениться только один раз во время выполнения

Ссылка: c-sharpcorner

...