Яка різниця між const і readonly в C #?


1362

Яка різниця між constі readonlyв C #?

Коли б ви використовували одне над іншим?


Я повинен був переглянути кілька відповідей, щоб знайти це посилання, але це добре. Ерік Ліпперт взяв на себе незмінність у C #
Френк Брайс

2
@donstack, насправді згідно з посиланням на C # , поле для читання тільки може бути призначене та перепризначене кілька разів у межах декларації поля та конструктора.
Marques

Відповіді:


1289

Крім очевидної різниці

  • маючи оголосити значення під час визначення значень constVS, readonlyможна обчислити динамічно, але їх потрібно призначити до виходу конструктора .. після цього його заморожують.
  • 'const's неявно 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. Усі клієнти не потрібно перекомпілювати.

Тож якщо ви впевнені, що значення константи не зміниться, використовуйте a const.

public const int CM_IN_A_METER = 100;

Але якщо у вас є константа, яка може змінюватися (наприклад, точність роботи) .. або коли виникаєте сумніви, використовуйте a readonly.

public readonly float PI = 3.14;

Оновлення: Аку потрібно згадати, адже він спочатку це зазначив. Також мені потрібно підключити те, де я це навчився. Ефективний C # - Білл Вагнер


77
staticТочка , здається, самий важливий і корисний пункт -consts are implicitly static
LCJ

28
Частина про опорні значення є найбільш важливою. Значення вартості можна оптимізувати за межами.
CodingBarfield

22
readonlyзмінні можуть бути змінені поза конструктором (відображення). Лише компілятор намагається перешкодити вам змінювати var поза конструктором.
Bitterblue

12
@ readonlyзмінні mini-me не можна змінювати після закінчення конструктора, навіть через відображення. Час виконання цього не виконує. Виконавча також відбувається не застосовувати , що ви не змінити string.Emptyдо "Hello, world!", але я до сих пір не буду стверджувати , що це робить string.Emptyзмінним, або що код не повинен припускати , що string.Emptyзавжди буде рядком нульової довжини.

7
blogs.msmvps.com/jonskeet/2014/07/16/… цікаво читати лише накладні витрати лише на читання
CAD блокується

275

Є ґутча з consts! Якщо ви посилаєтесь на константу з іншої збірки, її значення буде скомпільовано прямо у виклику. Таким чином, коли ви оновлюєте константу у посиланні на збірку, вона не змінюватиметься у виклику!


8
При декомпіляції (Reflector, ILSpy, ..) на постійну НІКОЛИ НІКОЛИ не посилається жодна, незалежно від тієї ж збірки чи іншої збірки, тому ви взагалі не можете проаналізувати використання константи у складеному коді.
springy76

159

Константи

  • Константи за замовчуванням статичні
  • Вони повинні мати значення під час компіляції (ви можете мати, наприклад, 3,14 * 2, але не можете викликати методи)
  • Може бути оголошено в межах функцій
  • Копіюються у кожну збірку, яка їх використовує (кожна збірка отримує локальну копію значень)
  • Може використовуватися в атрибутах

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

  • Повинно мати встановлене значення за часом закінчення конструктора
  • Оцінюються при створенні примірника

Статичні поля лише для читання

  • Оцінюються, коли виконання коду потрапляє на посилання класу (коли створюється новий екземпляр або виконується статичний метод)
  • Повинно мати оцінене значення до моменту, коли зроблено статичний конструктор
  • Не рекомендується ставити ThreadStaticAttribute на ці (статичні конструктори виконуватимуться лише в одному потоці і встановлюватимуть значення для його потоку; всі інші потоки матимуть це значення неініціалізованим)

58

Додамо лише, що 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
  }
}

Чи є якийсь інший тип відліку, ніж stringтой, який ви могли б використовувати як постійну?
springy76

Ви можете мати constтипи посилань, крім рядка, але константа може мати лише значення null.
Майк Рософт

40

Це пояснює це . Короткий зміст: const повинен бути ініціалізований під час оголошення, він може бути ініціалізований на конструкторі (і, таким чином, мати інше значення залежно від конструктора, який використовується).

РЕДАКТУВАННЯ: Дивіться дивовижну приналежність Гішу вище про тонку різницю


32

const: Не можна змінити ніде.

readonly: Це значення можна змінити лише в конструкторі. Неможливо змінити звичайні функції.


26

Існує невеликий готча з лише читанням. Поле для читання може бути встановлено кілька разів у межах конструкторів. Навіть якщо значення встановлено у двох різних ланцюгових конструкторах, все одно це дозволено.


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
    }
}

26

Постійний член визначається під час компіляції і не може бути змінений під час виконання. Константи оголошуються як поле з використанням 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;
     }
}

const

  • Вони не можуть бути оголошені як static(вони неявно статичні)
  • Значення константи оцінюється під час компіляції
  • константи ініціалізуються лише при оголошенні

лише для читання

  • Вони можуть бути як на рівні екземпляра, так і статичними
  • Значення оцінюється під час виконання
  • readonly може бути ініціалізовано в декларації або за допомогою коду в конструкторі

6
Вони не можуть бути статичними , вони статичними. Вам слід static const int i = 0;
уточнити,

Чи можете ви пояснити, чому constдекларації не можна робити всередині методів?
Мінь Тран

21

Конст - це константа часу компіляції, тоді як зчитування дозволяє лише обчислювати значення під час виконання та встановлювати в ініціалізаторі конструктора або поля. Отже, "const" завжди постійний, але "readlyly" читається лише після його призначення.

Ерік Ліпперт із команди C # має більше інформації про різні типи незмінності


15

Ось ще одне посилання, що демонструє, наскільки const не є безпечним для версії, чи релевантним для референтних типів.

Підсумок :

  • Значення вашої властивості const встановлюється під час компіляції і не може змінюватися під час виконання
  • Const не може бути позначений як статичний - ключове слово позначає, що вони є статичними, на відміну від полів для читання лише, які можуть.
  • Const не може бути нічого, крім значущих (примітивних) типів
  • Ключове слово для читання лише позначає поле як незмінне. Однак властивість можна змінити всередині конструктора класу
  • Ключове слово лише для читання може також поєднуватися зі статичним, щоб змусити його діяти так само, як const (принаймні на поверхні). Існує помітна різниця, коли ви дивитесь на ІЛ між ними
  • поля const позначені як "буквальне" в IL, тоді як readonly - "initonly"

11

Тільки для читання : значення можна змінювати через Ctor під час виконання. Але не через функцію члена

Постійний : За допомогою статичної дефолтності. Значення не можна змінювати з будь-якого місця (Ctor, Function, час виконання тощо. Ні-де)


дякую, що не змусив мене прочитати 4 абзаци лише для цих двох виїздів ...
Дон Чіддл,

9

Ще одна проблема: значення лише для читання можна змінити за допомогою "хибного" коду за допомогою відображення.

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

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


6

Я вважаю, що constзначення однакове для всіх об'єктів (і має бути ініціалізовано буквальним виразом), тоді як readonlyможе бути різним для кожної інстанції ...


5

Один з членів команди в нашому офісі надав наступні вказівки щодо використання const, static та readonly:

  • Використовуйте const, коли у вас є змінна типу, яку ви можете знати під час виконання (string literal, int, double, enums, ...), що ви хочете, щоб усі екземпляри або споживачі класу мали доступ до місця, де значення не повинно змінюватися.
  • Використовуйте статичні, коли у вас є дані, які ви хочете, щоб усі екземпляри або споживачі класу мали доступ до місця, де значення може змінюватися.
  • Використовуйте статичне читання лише тоді, коли у вас є змінна типу, яку ви не можете знати під час виконання (об'єкти), що ви хочете, щоб усі екземпляри або споживачі класу мали доступ до місця, де значення не повинно змінюватися.
  • Використовуйте лише для читання, коли у вас є змінна рівня екземпляра, яку ви будете знати під час створення об'єкта, яка не повинна змінюватися.

Останнє зауваження: поле const є статичним, але обернене не відповідає дійсності.


1
Я думаю, ти маєш на увазі "навпаки". Зворотним було б "поле, яке не є const, не є статичним". Що може бути, а може і не бути правдою. Зворотне, "статичне поле - це (завжди) const" - це неправда.
Майкл Блекберн

5

Вони обидва постійні, але const доступний і під час компіляції. Це означає, що одним із аспектів різниці є те, що ви можете використовувати const змінні як вхідні дані для конструкторів атрибутів, але не змінні лише для читання.

Приклад:

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
  • коли використовувати constабоreadonly

    • const

      • константа часу компіляції : абсолютна константа, значення встановлюється під час оголошення, знаходиться в самому коді IL
    • readonly

      • константа часу виконання : може бути встановлена ​​в конструкторі / init через конфігураційний файл, тобто App.config, але як тільки вона ініціалізується, її неможливо змінити

4

Змінні, позначені const, трохи більше, ніж сильно набрані #define макроси, під час компіляції посилання змінних const замінюються вбудованими буквальними значеннями. Як наслідок, таким чином можна використовувати лише певні вбудовані примітивні типи значень. Змінні, позначені лише для читання, можна встановлювати в конструкторі під час виконання, і їх необхідність лише для читання застосовується і під час виконання. З цим пов'язана незначна вартість продуктивності, але це означає, що ви можете використовувати лише для читання лише з будь-яким типом (навіть із типовими типами).

Крім того, змінні const за своєю суттю є статичними, тоді як змінні, що читаються тільки, за бажанням можуть бути конкретними.


Додано, що consts сильно набрані #define макроси. В іншому випадку ми можемо відлякати всіх людей, що знаходяться на С та С ++. :-)
Джейсон Бейкер

4

КОНСТ

  1. Ключове слово const може застосовуватися до полів або локальних змінних
  2. Ми повинні призначити поле const під час декларування
  3. Ніякої пам'яті не виділено, оскільки значення const вбудовується в сам код IL після компіляції. Це ніби знайти всі входження змінної const і замінити її значенням. Тож код IL після компіляції матиме жорстко закодовані значення замість змінних const
  4. Конституція в C # за замовчуванням статична.
  5. Значення постійне для всіх об'єктів
  6. Існує проблема версії dll. Це означає, що щоразу, коли ми змінюємо загальнодоступну змінну const або властивість, (насправді це не передбачається змінювати теоретично), будь-який інший dll або збірка, яка використовує цю змінну, повинна бути перебудована
  7. Лише вбудовані типи C # можуть бути оголошені постійними
  8. Поле const не може бути передано як параметр ref або out

Лише для читання

  1. Ключове слово readonly застосовується лише до полів, не локальних змінних
  2. Ми можемо призначити поле для читання лише під час оголошення або в конструкторі, а не будь-якими іншими методами.
  3. динамічна пам'ять, що виділяється лише для полів для читання, і ми можемо отримати значення під час виконання.
  4. Readonly належить до створеного таким чином об'єкта, доступ до якого здійснюється лише через екземпляр класу. Щоб зробити його членом класу, нам потрібно додати статичне ключове слово перед читанням.
  5. Значення може бути різним залежно від використовуваного конструктора (оскільки воно належить об'єкту класу)
  6. Якщо ви оголошуєте непомітивні типи (тип посилання) як лише прочитане, посилання є незмінним, а не об'єктом, який він містить.
  7. Оскільки значення отримане під час виконання, не існує проблеми з версією dll з полями / властивостями, які читаються тільки.
  8. Ми можемо передавати поле для читання лише як параметри ref або out у контексті конструктора.

3

Ще одна гатча .

Оскільки const дійсно працює лише з базовими типами даних, якщо ви хочете працювати з класом, ви можете відчувати себе «змушеним» використовувати ReadOnly. Однак остерігайтеся пастки! ReadOnly означає, що ви не можете замінити об'єкт іншим об'єктом (ви не можете змусити його посилатися на інший об’єкт). Але будь-який процес, який має посилання на об'єкт, вільний для зміни значень всередині об'єкта!

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


Так, це більше загальна тема. Якщо у вас є лише властивість, що виставляє arraylist, ви все одно можете змінити arraylist. Ви не можете встановити іншого масиву для цього властивості, але ви не можете перешкодити користувачеві змінювати його.
Gishu

3

A constмає бути жорстко закодованим , де це readonlyможе бути встановлено в конструкторі класу.


3

Існує помітна різниця між полями 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

лише заново можна оголосити статичним, але не є необхідним. Під час декларації не потрібно ініціалізувати. Його значення можна призначити або змінити за допомогою конструктора. Отже, це дає перевагу при використанні як член класу екземпляра. Дві різні інстанції можуть мати різне значення поля лише для читання. Для колишнього -

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

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

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


Я щиро сумніваюся, що це правда ... Я піду перевірити.
ljs

це один із 50 конкретних способів поліпшити свій C # - amazon.co.uk/Effective-Specific-Ways-Improve-Your/dp/0321245660/…
Russ Cam


@Andrew Заяц - так, я щойно перевірив. Я дуже здивований, це справжня гатча, я справді дуже здивований тим, вражений, що так ...!
ljs

Однак я заперечую проти використання слова вказівника. Це не покажчик, це посилання, і є різниця в C #, оскільки ви можете маніпулювати некерованими вказівниками в небезпечному режимі, тому важливо розрізняти два.
ljs

2

Постійний

Нам потрібно надати значення поля const, коли воно визначене. Потім компілятор зберігає значення константи в метаданих збірки. Це означає, що константа може бути визначена лише для примітивного типу, наприклад, булева, char, байт тощо. Константи завжди вважаються статичними членами, а не членами екземплярів.

Лише для читання

Поля для читання лише можна вирішити лише під час виконання. Це означає, що ми можемо визначити значення для значення, використовуючи конструктор для типу, в якому оголошено поле. Перевірка проводиться компілятором, що поля, які читаються тільки не записуються іншим способом, крім конструктора.

Більше про обидва пояснено тут у цій статті


1

В основному; ви можете призначити статичне поле для читання лише непостійному значенню під час виконання, тоді як const повинен присвоювати постійне значення.


1

Const і readonly схожі, але вони не зовсім однакові. Поле const - це константа часу компіляції, тобто це значення може бути обчислено під час компіляції. Поле для читання дає змогу отримати додаткові сценарії, коли деякий код повинен бути запущений під час побудови типу. Після побудови поле для читання тільки не може бути змінено.

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

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

оскільки значення, такі як 3.14 і 0, є константами часу компіляції. Однак розглянемо випадок, коли ви визначаєте тип і хочете надати деякі його попередні файли. Наприклад, ви можете визначити клас кольорів та надати "константи" для таких кольорів, як чорний, білий та ін. Це неможливо зробити з членами const, оскільки права сторона не є константами часу компіляції. Це можна зробити за допомогою регулярних статичних членів:

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 не спілкуватися з ним, можливо, замінюючи значення Чорно-Біле. Зайве говорити, що це може викликати побоювання у інших клієнтів класу Color. Функція "лише для читання" стосується цього сценарію. Просто вводячи в декларації ключове слово, що читається лише ми, ми зберігаємо гнучку ініціалізацію, не дозволяючи клієнтському коду вимикатись.

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 завжди є статичними, тоді як член, що читає лише, може бути статичним чи ні, як звичайне поле.

Можна використовувати одне ключове слово для цих двох цілей, але це призводить до проблем з версіями або до продуктивності. Припустимо на мить, що для цього ми використовували одне ключове слово (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 впевнений, що зміна струму завжди буде дорівнює нулю. Використання const і readonly дозволяє розробнику A вказати наміри. Це сприяє кращій поведінці версій, а також кращій роботі.


1

ReadOnly: значення буде ініціалізовано лише один раз із конструктора класу.
const: може ініціалізуватися в будь-якій функції, але лише один раз


1

Різниця полягає в тому, що значення статичного поля лише для читання встановлюється під час виконання, тому воно може мати різне значення для різних виконань програми. Однак значення поля const встановлюється константа часу компіляції.

Пам’ятайте: Для типів посилань в обох випадках (статичний і екземпляр) модифікатор, що читає лише, не дозволяє вам призначити нове посилання на поле. Це спеціально не робить непорушним об'єкт, на який вказується посилання.

Для детальної інформації зверніться до C # Запитання на цю тему: http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx


1

Постійні змінні оголошуються та ініціалізуються під час компіляції. Значення неможливо змінити після підопічних. Змінні лише для читання будуть ініціалізовані лише із конструктора Static класу. Тільки для читання використовується лише тоді, коли ми хочемо призначити значення під час виконання.


1

Const : Абсолютне постійне значення протягом життя програми.

Readonly : Це може бути змінено за часом роботи.


1
Ваше визначення "Readonly", яке воно може змінити, хибне. Я думаю, що під "змінити" ви мали на увазі "встановити", наприклад "це можна встановити під час виконання".
Ахмед

0

Одне додати до того, що люди сказали вище. Якщо у вас є збірка, що містить значення для читання тільки (наприклад, для readonly MaxFooCount = 4;), ви можете змінити значення, яке бачать викликові збірки, доставляючи нову версію цієї збірки з іншим значенням (наприклад, лише для читання MaxFooCount = 5;)

Але з const, він буде складений в код абонента, коли абонент був складений.

Якщо ви досягли цього рівня кваліфікації на C #, ви готові до книги Білла Вагнера "Ефективний C #: 50". Спеціальні способи поліпшити свій C #, який детально відповідає на це питання (та 49 інших речей).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.