Статична реакція лише проти const


1386

Я читав навколо constі про static readonlyполя. У нас є кілька класів, які містять лише постійні значення. Використовується для різних речей у нашій системі. Тож мені цікаво, чи моє спостереження правильне:

Чи повинні такі види постійних цінностей завжди бути static readonlyдля всього, що є загальнодоступним? І використовувати лише constдля внутрішніх / захищених / приватних цінностей?

Що ви порадите? Чи, можливо, я навіть не використовую static readonlyполя, а скоріше, можливо, використовувати властивості?


5
Ось дуже цікавий окремий випадок, який я щойно знайшов на користь static readonly: спробуйте використовувати const всередині, IEnumeratorякий викликає неможливість повторної перевірки, yield і ви отримаєте жахливу "внутрішню помилку компілятора" . Я не перевіряв код за межами Unity3D, але я вірю, що це моно або .NET- помилка . Але це питання # .
Крегокс

2
Можливий дублікат Яка різниця між const і readonly?
nawfal

8
Ще одна відмінність полягає в тому, що ви можете використовувати рядок const в комутаторі, але не статичну рядок для читання лише
flagg19

7
static readonlyне може бути використаний у switch-caseоператорі як caseзмінна, constдля цього потрібно.
Мостафіз Рахман

3
static readonlyтакож не можна використовувати як параметр атрибута
Dread Boy

Відповіді:


940

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

constзначення спалюються безпосередньо на сайт виклику; це подвійний край:

  • марно, якщо значення вибирається під час виконання, можливо, з config
  • якщо ви зміните значення const, вам потрібно відновити всіх клієнтів
  • але це може бути швидше, оскільки це дозволяє уникнути виклику методу ...
  • ... що, можливо, інколи було наголошене JIT

Якщо значення ніколи не зміниться, то const є нормальним - Zeroтощо роблять розумні витрати; p Окрім цього, staticвластивості більш поширені.


13
Чому власність над полем? Якщо це незмінний клас, я не бачу різниці.
Майкл Хедґпет

73
@Michael - ті ж причини, що і завжди; вона приховує реалізацію. Ви можете (пізніше) виявити, що вам потрібно ліниво завантажуватись, базуватися на конфігурації, фасаді чи будь-що інше. Насправді, або часто було б добре ...
Marc Gravell

42
@CoffeeAddict за визначенням, константа не витягує значення з конфігураційного файлу; він записується як буквальний під час компіляції. Єдиний спосіб використовувати константу під час виконання - це за допомогою відображення над полями. Будь-який інший раз, коли ви намагаєтесь його використовувати, компілятор як уже замінив ваше постійне використання для буквального використання; тобто, якщо метод у вашому коді використовує 6 констант, і ви перевіряєте його як IL, не буде згадок про постійні пошуки; буквальні значення просто завантажуватимуться in situ
Marc Gravell

37
@MarcGravell - ПОПЕРЕДЖЕННЯ: readonlyполя не можна використовувати в операторах перемикання / справи, натомість вони потрібні const.
Лучано

7
@didibus Зміна поля на властивість насправді порушує API. Поле в C # ефективно діє як змінна, тоді як властивість у C # є помічником синтаксису для написання методу getter та / або методу setter. Ця різниця важлива при участі інших зборів. Якщо ви змінили поле на властивість, а інші збірки залежали від цього поля, то ці інші збірки потрібно перекомпілювати.
Стівен Бугер

237

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


5
Тому я думаю, як дехто згадував або на це натякав, може бути розумним використовувати const лише для значень, які насправді добре відомі константи, якщо вони оприлюднені, інакше вони повинні бути зарезервовані для внутрішнього, захищеного чи приватного доступу.
jpierson

1
@Dio Причина все ще існує в тому, що вона сама по собі не є проблемою - це щось, про що слід пам’ятати, але здатність вкладати суперечки через межі складання - це корисна річ. Це справді лише питання справді зрозуміти, що "константа" означає "це ніколи не зміниться".
Майкл Стум

1
@MichaelStum Добре, я не повинен називати це "проблемою". У моїй роботі я маю const і ділю його на всі складання, але я перекомпілюю для кожного розгортання або доставки коду. Тим не менш, цей факт, безумовно, варто взяти до відома.
Діо Пхунг

1
Отже, загалом internal constабо public static readonlyзалежно від бажаної видимості.
Ірідайн

2
@Iiridayn Так, це не поганий погляд на це. Є кілька кращих випадків, які слід врахувати (наприклад, якщо використовується Reflection або якщо для атрибута потрібне значення), і для цього є дійсні способи використання public const(наприклад, будь-що, що є частиною стандарту. Щоразу, коли я працюю з XML, є файл іменних просторів з купою public const string.) Але загалом, його public constслід використовувати лише після належного розгляду наслідків.
Майкл Стум

199

Ще кілька релевантних речей, які слід зазначити:

const int a

  • повинні бути ініціалізовані.
  • ініціалізація повинна бути під час компіляції .

readonly int a

  • може використовувати значення за замовчуванням без ініціалізації.
  • ініціалізація може бути здійснена під час виконання (Правка: лише в конструкторі).

39
в межах ctorєдиного.
Аміт Кумар Гош

1
Не тільки в конструкторі, але і в декларації ( docs.microsoft.com/en-us/dotnet/csharp/language-reference/… ).
deChristo

176

Це лише доповнення до інших відповідей. Не буду їх повторювати (зараз через чотири роки).

Бувають ситуації, коли a constі non-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збирається порівняти a System.Int16з a System.Int32, і оскільки типи часу навіть не згодні, це дасть результат false.

Ми робимо висновок, що в деяких (рідкісних) випадках зміна constчлена типу на static readonlyполе (або в інший спосіб, коли це можливо) може змінити поведінку програми.


17
Гарне доповнення до прийнятої відповіді. Я хотів би додати, що правильна конвертація типів даних та інші подібні вказівки (як, наприклад, спробу вилову тощо) повинні бути частиною досвідчених програмістів, а не залишатись компілятором. Тим не менш, я дізнався щось нове звідси. Дякую.
Uknight

Нічого собі, я довго програмував на C # і ніколи не здогадувався, що const int в межах короткого може бути неявно перетворений на короткий. Треба сказати, що це досить дивно. Я люблю C #, але ці дивні невідповідності, які, здається, не додають великої цінності, але додають багато необхідної сили мозку для постійного розгляду, можуть викликати роздратування, особливо для початківців.
Майк Мариновський

@MikeMarynowski Досить правда. Але я думаю, що вони прийняли це правило (серед інших причин), щоб зробити заяву short x = 42;законною. Тому що там у вас є int, а саме буквальне 42, яке неявно перетворюється на short x. Але тоді вони, можливо, обмежили це лише числовими буквами; однак вони вирішили дозволити також такі речі, як, short x = y;де yце визначено як const int y = 42;, і тоді вони закінчилися з цим.
Джеппе Стіг Нільсен

87

Варто зазначити, що const обмежується примітивними / значеннями типів (винятком є ​​рядки)


30
Насправді він constможе бути використаний і для інших типів, за винятком того, що його потрібно ініціалізувати до нуля, що робить його марним :)
nawfal

6
виняток як у System.Exception? :)
Мемет Олсен

4
@nawfal Більш точно, тільки типи значень , для яких constможуть бути використані, є sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, плюс будь-які enumтипи. constне можна використовувати для інших типів значень, таких як DateTimeабо TimeSpanабо BigInteger. Він також не може бути використаний для IntPtrструктури (дехто вважає "примітивним" типом; термін примітивний тип заплутаний у C #). ↵↵ constМожна використовувати для всіх типів еталонів . Якщо тип є string, будь-яке значення рядка можна вказати. В іншому випадку значення повинно бути null.
Джеппе Стіг Нільсен

@JeppeStigNielsen - Я недавно була суперечка з servy про це - він вказав на те , що ви можете зробити що - небудь (значення і посилальні типи) , constвикористовуючи default. Для structтипів це екземпляр, у якого всі його члени встановлені за замовчуванням.
Вай Ха Лі

28

Статичний лише для читання : значення можна змінювати за допомогою staticконструктора під час виконання. Але не через функцію члена

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

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

Ви можете ознайомитися з моїми репортажами: C # .


1
Погані новини ... зламане посилання!
Fer R


Хороші фрагменти Сіам ভাই :)
Мухаммед Ашикуззаман

25

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

Короткий і чіткий посилання MSDN тут


16

constі readonlyподібні, але вони не зовсім однакові.

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

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

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


12

Моя перевага - використовувати const, коли я можу, що, як було сказано вище, обмежується буквальними виразами або чимось, що не потребує оцінки.

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


7

Const: Const - це не що інше, як "константа", змінна значення якої є постійною, але під час компіляції. І обов’язково присвоїти йому значення. За замовчуванням const є статичним, і ми не можемо змінити значення змінної const у всій програмі.

Static ReadOnly: Значення змінної типу Static Readonly може бути призначене під час виконання або присвоєно під час компіляції та змінено під час виконання. Але значення цієї змінної можна змінити лише в статичному конструкторі. І не можна змінювати далі. Він може змінюватися лише один раз під час виконання

Довідка: c-sharcorner


6

Статичне поле лише для читання є вигідним, коли виставляти іншим збіркам значення, яке може змінитися в більш пізній версії.

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

public const decimal ProgramVersion = 2.3;

Якщо Yпосилання на збірку Xі використовує цю константу, значення 2.3 буде Yскомпоновано в збірку при компіляції. Це означає, що якщо Xпізніше буде перекомпільовано з постійною Yвеличиною 2,4, все одно буде використовувати старе значення 2,3, поки не Yбуде перекомпільовано. Статичне поле для читання лише дозволяє уникнути цієї проблеми.

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


3

const:

  1. значення слід надати після декларування
  2. компілювати постійну часу

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

  1. Значення може бути задане після оголошення або під час виконання з використанням конструкторів. Значення може змінюватися залежно від використовуваного конструктора.
  2. постійний час роботи

3

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

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

Статичні лише для читання : статичні значення для змін, що читаються, ми можемо визначити під час декларування, а також лише через статичний конструктор, але не з будь-яким іншим конструктором. Ці змінні ми також можемо отримати доступ без створення екземпляра класу (як статичних змінних).

static readonly стане кращим вибором, якщо нам доведеться споживати змінні в різних збірках. Перевірте повну інформацію нижче за посиланням

https://www.stum.de/2009/01/14/const-strings-a-very-convenient-way-to-shoot-yourself-in-the-foot/


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

Не DV, але, можливо, ця відповідь насправді нічого не додає до вже вичерпних відповідей.
Марк Л.

Дійсно, пам’ятайте, що в Java ще в кінці 90-х у нас в проекті було декілька людей, які виробляли різні банки з файлами класу, які взаємоділи (
посилалися

2

Існує незначна різниця між полями const і static readonly в C # .Net

const необхідно ініціалізувати зі значенням під час компіляції.

const за замовчуванням статичний і його потрібно ініціалізувати постійним значенням, яке згодом неможливо змінити. Його не можна використовувати з усіма типами даних. Для колишнього 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

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


0

Константи, як випливає з назви, поля, які не змінюються і зазвичай визначаються статично під час компіляції в коді.

Змінні лише для читання - це поля, які можуть змінюватися за певних умов.

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

Вони не можуть бути змінені після ініціалізації в умовах, зазначених вище.

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

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


0

Const (визначається під час компіляції) може використовуватися в тих випадках, коли статичний режим для читання не може, як, наприклад, у операторах переключення чи конструкторах атрибутів. Це пояснюється тим, що поля, які читаються лише, вирішуються лише під час виконання, а деякі конструкції коду вимагають забезпечення часу компіляції. Число статики можна обчислити в конструкторі, що часто є важливою і корисною справою. Різниця є функціональною, як і їх використання на мою думку.

Що стосується розподілу пам’яті, щонайменше з рядками (є еталонним типом), схоже, немає різниці в тому, що обидва є інтернованими та будуть посилатися на один інтернований екземпляр.

Особисто я за замовчуванням є лише статичним, оскільки він має більш смисловий та логічний сенс для мене, тим більше, що більшість значень не потрібні під час компіляції. І, до речі, статистика публічного читання взагалі не є незвичайною або рідкістю, як зазначено у позначеній відповіді: наприклад, System.String.Emptyце одна.


0

Ще одна відмінність між оголошенням const і статичним readonly полягає в розподілі пам'яті.

Статичне поле належить до типу об'єкта, а не до екземпляра цього типу. Як результат, як тільки в класі вперше посилається, статичне поле буде "жити" в пам'яті протягом решти часу, і той самий екземпляр статичного поля буде посилатися на всі екземпляри типу.

З іншого боку, const поле "належить до екземпляра типу.

Якщо пам’ять про розселення важливіше для вас, вважайте за краще використовувати const . Якщо швидкість, то використовуйте статичну читання лише .

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