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

Мне понравился ответ из @Mahomedalid, кроме этого факта, сообщенного в комментарии от @Bill Karwin. Возможная проблема, поднятая @Jan Koritak, верна. Я столкнулся с этим, но я нашел для этого трюк и просто хочу поделиться ею здесь, для тех, кто сталкивается с проблемой.

мы можем заменить функцию REPLACE предложением where в подзапросе инструкции «Подготовить»:

Использование моей таблицы и имени столбца

SET @SQL = CONCAT('SELECT ', (SELECT GROUP_CONCAT(COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'users' AND COLUMN_NAME NOT IN ('id')), ' FROM users');
PREPARE stmt1 FROM @SQL;
EXECUTE stmt1;

Итак, это исключает только поле id, но не company_id

Надеюсь, это поможет любому, кто ищет решение.

С уважением

1203
задан Praveen 6 November 2013 в 11:56
поделиться

18 ответов

Кроме очевидной разницы [1 129]

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

Обновление: Aku должен получить упоминание, потому что он указал на это сначала. Также я должен включиться, где я изучил это.. Эффективный C# - Bill Wagner

1162
ответ дан Irshad 6 November 2013 в 11:56
поделиться

Основное отличие - то, что Константа является эквивалентом C #DEFINE. Число буквально получает предварительный компилятор крыла, которым заменяют. Только для чтения на самом деле рассматривается как переменную.

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

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

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

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

Hope это помогает, Alan.

0
ответ дан AlanR 6 November 2013 в 11:56
поделиться

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

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

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

0
ответ дан Anthony 6 November 2013 в 11:56
поделиться

Другой глюк .

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

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

3
ответ дан Mark T 6 November 2013 в 11:56
поделиться

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

Пример:

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; }
  }
}
5
ответ дан Hallgrim 6 November 2013 в 11:56
поделиться

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

260
ответ дан Appulus 6 November 2013 в 11:56
поделиться

Константы

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

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

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

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

  • оценены, когда выполнение кода поражает ссылку класса (когда новый экземпляр создается, или статический метод выполняется)
  • , Должен иметь оцененное значение к тому времени, когда статический конструктор сделан
  • , не рекомендуется поместить ThreadStaticAttribute на них (статические конструкторы будут выполняться в одном потоке только и установят значение для его потока; все другие потоки будут иметь это значение неинициализированным)
144
ответ дан Shantanu Gupta 6 November 2013 в 11:56
поделиться

Только для добавления 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
  }
}
54
ответ дан 6 November 2013 в 11:56
поделиться

Это объясняет его . Сводка: константа должна быть инициализирована во время объявления, только для чтения может быть инициализирован на конструкторе (и таким образом иметь различное значение в зависимости от используемого конструктора).

РЕДАКТИРОВАНИЕ: Посмотрите глюк Gishu выше для тонкого различия

37
ответ дан Vinko Vrsalovic 6 November 2013 в 11:56
поделиться

Отмеченная константа переменных немного больше, чем #define макросы со строгим контролем типов, во время компиляции ссылки на переменную константы заменяются встроенными литеральными значениями. Как следствие только определенные встроенные примитивные типы значения могут использоваться таким образом. Переменные, отмеченные только для чтения, могут быть установлены, в конструкторе, во времени выполнения, и их только для чтения осуществляется во время времени выполнения также. Существует некоторая незначительная стоимость производительности, связанная с этим, но это означает, что можно использовать только для чтения с любым типом (даже ссылочные типы).

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

4
ответ дан Jason Baker 6 November 2013 в 11:56
поделиться

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


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
    }
}
24
ответ дан Mike Two 6 November 2013 в 11:56
поделиться

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

6
ответ дан Daren Thomas 6 November 2013 в 11:56
поделиться

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

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

Одно заключительное примечание: поле константы статично, но инверсия не верна.

5
ответ дан Scott Lawrence 6 November 2013 в 11:56
поделиться

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

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

20
ответ дан Wheelie 6 November 2013 в 11:56
поделиться

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

Сводка :

  • значение Вашего свойства константы установлено во время компиляции и не может измениться во времени выполнения
  • , Константа не может быть отмечена как статичная - ключевое слово обозначает, что они статичны, в отличие от полей только для чтения, которые могут.
  • Константа может быть ничем кроме значения (примитивные) типы
  • , ключевое слово только для чтения отмечает поле как неизменное. Однако свойство может быть изменено в конструкторе класса
  • только для чтения, только ключевое слово может также быть объединено с помехами, чтобы заставить его действовать таким же образом как константа (по крайней мере на поверхности). Существуют заметные различия при рассмотрении IL между два
  • , поля константы отмечены, поскольку "литерал" в IL, в то время как только для чтения является "initonly"
15
ответ дан Chris S 27 September 2019 в 08:24
поделиться
  • 1
    Спасибо. Это требует для имения надлежащего pom.xml. Это - думание, что я избежал бы. Вы знаете способ получить тот же результат, не определяя англичанина? – Andrea Francia 31 August 2010 в 02:58

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

1
ответ дан 22 November 2019 в 20:31
поделиться

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

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

2
ответ дан 22 November 2019 в 20:31
поделиться

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

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

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

8
ответ дан 22 November 2019 в 20:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: