Статическое чтение только против const

1197

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

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

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

Показать ещё 3 комментария
Теги:
constants

14 ответов

826
Лучший ответ

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

значения const сожжены непосредственно на сайте call-сайта; это двойное очертание:

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

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

  • 11
    Почему собственность над полем? Если это неизменный класс, я не вижу разницы.
  • 64
    @ Михаил - те же причины, что и всегда; это скрывает реализацию. Вы можете (позже) обнаружить, что вам нужно загружаться лениво, на основе конфигурации, фасада или чего-то еще. На самом деле, либо часто будет хорошо ...
Показать ещё 13 комментариев
189

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

  • 4
    Поэтому я думаю, что, как некоторые упоминали или упоминали, может быть целесообразно использовать const только для значений, которые на самом деле являются хорошо известными константами, если они обнародованы, в противном случае они должны быть зарезервированы для внутренней, защищенной или закрытой области доступа.
  • 1
    @Dio Причина, по которой он все еще существует, заключается в том, что он не является проблемой как таковой - это то, о чем нужно знать, но возможность встроить концы через границы сборки - хорошая вещь для производительности. Это просто вопрос понимания, что «константа» означает «она никогда не изменится».
Показать ещё 5 комментариев
173

Некоторые другие вещи

const int a

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

readonly int a

  • может использовать значение по умолчанию без инициализации
  • инициализация может выполняться во время выполнения
  • 29
    только внутри ctor .
149

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

Существуют ситуации, когда a 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 является константой, и при условии, что компилятор С# проверяет, что его значение находится в диапазоне от short (который 42 есть). См. Неявные преобразования константных выражений в Спецификации языка С#. Поэтому необходимо учитывать как перегрузки. Перегрузка Equals(short) является предпочтительной (любой short является object, но не все object являются short). Поэтому y преобразуется в short и используется перегрузка. Тогда Equals сравнивает два short с одинаковым значением и дает True.

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

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

  • 16
    Хорошее дополнение к принятому ответу. Я хотел бы добавить, что правильное преобразование типов данных и другие подобные рекомендации (такие как try catch и т. Д.) Должны быть одним из основных продуктов опытных программистов, а не предоставляться компилятору. Тем не менее, я узнал что-то новое отсюда. Спасибо.
  • 0
    Ух ты, я давно программирую на C # и никогда бы не подумал, что const int в диапазоне short может быть неявно преобразован в short. Я должен сказать, что это довольно странно. Я люблю C #, но эти странные несоответствия, которые, кажется, не добавляют большой ценности, но добавляют много необходимой умственной силы, чтобы постоянно их рассматривать, могут раздражать, особенно для начинающих.
Показать ещё 1 комментарий
78

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

  • 25
    На самом деле const может быть использован и для других типов, за исключением того, что он должен быть инициализирован нулем, что делает его бесполезным :)
  • 6
    исключение как в System.Exception ? :)
Показать ещё 2 комментария
22

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

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

16

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

Константа: По умолчанию static. Значение не может быть изменено нигде (Ctor, Function, runtime etc no-where).

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

Вы можете посмотреть мои типы репо: С#.

  • 1
    Плохие новости ... битая ссылка!
  • 2
    @FerR там вы идете: github.com/yeasin90/advanced-csharp/blob/master/CSharpAdvanced/…
Показать ещё 1 комментарий
13

const и readonly похожи, но они не совсем то же самое.

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

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

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

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

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. Функция "только для чтения" рассматривает этот сценарий.

Просто введя ключевое слово 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);
}

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

Для этих двух целей можно использовать одно ключевое слово, но это приводит либо к проблемам с версией, либо к проблемам с производительностью. Предположим на мгновение, что мы использовали одно ключевое слово для этого (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 положителен, что AC всегда будет равен нулю. Использование как const, так и readonly позволяет разработчику A указать намерение. Это улучшает поведение версий, а также повышает производительность.

11

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

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

  • 2
    Почему const ваш первый выбор? только из-за производительности?
6

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

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

public const decimal ProgramVersion = 2.3;

Если сборка Y ссылается на X и использует эту константу, значение 2.3 будет запекаться в сборку Y при компиляции. Это значит, что если X позже перекомпилируется с константой, установленной в 2.4, Y будет по-прежнему используйте старое значение 2.3 до тех пор, пока Y не перекомпилируется. Статический поле readonly позволяет избежать этой проблемы.

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

5

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

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

Ссылка: c-sharpcorner

3

Уст:

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

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

  • Значение
  • может быть задано при объявлении или во время выполнения с использованием конструкторов. Значение может варьироваться в зависимости от используемого конструктора.
  • постоянная времени выполнения
2

Существует незначительная разница между константными и статическими полями readonly в С#.Net

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

const по умолчанию статический и должен быть инициализирован с постоянным значением, которое впоследствии не может быть изменено. Он не может использоваться со всеми типами данных. Для ex-DateTime. Он не может использоваться с типом данных DateTime.

public const DateTime dt = DateTime.Today;  //throws compilation error
public const string Name = string.Empty;    //throws compilation error
public static readonly string Name = string.Empty; //No error, legal

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

1

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

Только для чтения переменные - это поля, которые могут меняться при определенных условиях.

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

Они не могут быть изменены после инициализации в указанных выше условиях.

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

Кроме того, еще одно важное отличие состоит в том, что константа принадлежит классу, а переменная, доступная только для чтения, принадлежит экземпляру!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню