У .Net чому String.Empty читається лише замість константи? Мені просто цікаво, чи хтось знає, які міркування стояли за цим рішенням.
У .Net чому String.Empty читається лише замість константи? Мені просто цікаво, чи хтось знає, які міркування стояли за цим рішенням.
Відповіді:
Причина, яка static readonly
використовується замість цього const
, пов’язана з використанням некерованого коду, про що вказує Microsoft у випуску загальної мовної інфраструктури загальної мови 2.0 . Файл для перегляду є sscli20\clr\src\bcl\system\string.cs
.
Постійна константа містить значення порожнього рядка. Нам потрібно викликати конструктор String, щоб компілятор не позначив це як буквальний.
Позначення цього буквально означатиме, що воно не відображається як поле, до якого ми можемо отримати доступ з рідних.
Я знайшов цю інформацію з цієї зручної статті у CodeProject .
String.Empty
роздумую над тим, щоб більше не використовувати цю причину.
Думаю, тут багато плутанини та поганих реакцій.
Поперше, const
поля - це static
члени ( не члени екземпляра ).
Перевірте розділ 10.4 Константи специфікації мови C #.
Незважаючи на те, що константи вважаються статичними членами, константа декларування не вимагає і не дозволяє статичний модифікатор.
Якщо public const
члени статичні, не можна вважати, що константа створить новий Об'єкт.
Враховуючи це, наступні рядки коду роблять точно те саме, що стосується створення нового Об'єкта.
public static readonly string Empty = "";
public const string Empty = "";
Ось примітка від Microsoft, яка пояснює різницю між двома:
Ключове слово для читання лише відрізняється від ключового слова const. Поле const може бути ініціалізовано лише при оголошенні поля. Поле для читання можна ініціалізувати або в декларації, або в конструкторі. Тому поля, що читаються тільки можуть мати різні значення залежно від використовуваного конструктора. Крім того, хоча поле const є константою часу компіляції, поле readonly може використовуватися для констант виконання, ...
Тож я вважаю, що єдина правдоподібна відповідь тут - це Джефф Йейтс.
const string
і static readonly string
роблю те саме. Значення const замінюються в зв'язаному коді, тоді як статичні значення, що зчитуються лише, посилаються. Якщо у вас є const
бібліотека A, яка використовується бібліотекою B, бібліотека B замінить усі посилання на цю const
змінну своїм буквальним значенням; якби ця змінна була static readonly
замість неї, вона посилалася б і її значення визначалося під час виконання.
String.Empty read only instead of a constant?
Якщо ви робите будь-який рядок постійним , компілятор замінюється фактично рядком скрізь, де ви його називаєте, і ви заповнюєте свій код тією ж строкою всюди, і коли код працює, потрібно також знову і знову читати цю рядок з іншої пам'яті дані.
Якщо ви залишаєте рядок для читання лише в одному місці, оскільки вона є String.Empty
, програма зберігає ту саму рядок лише на одному місці і читає її, або посилається на неї - зберігаючи дані в пам'яті як мінімум.
Також якщо ви компілюєте будь-який dll, використовуючи String.Empty як const, і з будь-якої причини зміну String.Empty, тоді скомпільований dll більше не буде працювати однаково, тому що cost
зробіть внутрішній код, щоб насправді зберегти копію рядка на кожен дзвінок.
Дивіться цей код, наприклад:
public class OneName
{
const string cConst = "constant string";
static string cStatic = "static string";
readonly string cReadOnly = "read only string";
protected void Fun()
{
string cAddThemAll ;
cAddThemAll = cConst;
cAddThemAll = cStatic ;
cAddThemAll = cReadOnly;
}
}
компілятор прийде як:
public class OneName
{
// note that the const exist also here !
private const string cConst = "constant string";
private readonly string cReadOnly;
private static string cStatic;
static OneName()
{
cStatic = "static string";
}
public OneName()
{
this.cReadOnly = "read only string";
}
protected void Fun()
{
string cAddThemAll ;
// look here, will replace the const string everywhere is finds it.
cAddThemAll = "constant string";
cAddThemAll = cStatic;
// but the read only will only get it from "one place".
cAddThemAll = this.cReadOnly;
}
}
і дзвінок на збори
cAddThemAll = cConst;
0000003e mov eax,dword ptr ds:[09379C0Ch]
00000044 mov dword ptr [ebp-44h],eax
cAddThemAll = cStatic ;
00000047 mov eax,dword ptr ds:[094E8C44h]
0000004c mov dword ptr [ebp-44h],eax
cAddThemAll = cReadOnly;
0000004f mov eax,dword ptr [ebp-3Ch]
00000052 mov eax,dword ptr [eax+0000017Ch]
00000058 mov dword ptr [ebp-44h],eax
Правка: виправлена помилка друку
Ця відповідь існує в історичних цілях.
Спочатку:
Тому що String
це клас і тому не може бути константою.
Розширене обговорення:
Для перевірки цієї відповіді було забито багато корисного діалогу, і замість того, щоб видалити цей вміст, відтворюється безпосередньо:
У .NET (на відміну від Java) рядок і String точно однакові. І так, ви можете мати лінійні лінійні константи в .NET - DrJokepu 3 лютого '09 о 16:57
Ви говорите, що клас не може мати константи? - StingyJack 3 лютого '09 о 16:58
Так, об’єкти повинні використовуватись лише для читання. Лише структури можуть робити константи. Я думаю, що коли ви використовуєте
string
замістьString
компілятора, це змінює const на лише для читання. Все, що стосується задоволення програмістів C. - Гаррі Шутлер 3 лютого '09 о 16:59tvanfosson просто пояснив це дещо докладніше. "X не може бути константою, тому що містить Y - клас", був трохи занадто контекстним;) - Леонідас 3 лютого '09 о 17:01
string.Empty - це статична властивість, яка повертає екземпляр класу String, а саме порожній рядок, а не сам клас string. - tvanfosson 3 лютого '09 о 17:01
Empty - це лише екземпляр, що читається (це не властивість) класу String. - сенфо 3 лютого '09 о 17:02
Болить голова. Я все ще думаю, що я правий, але зараз я менш впевнений. Дослідження потрібно сьогодні! - Гаррі Шутлер 3 лютого '09 о 17:07
Порожній рядок - це екземпляр класу string. Empty - це статичне поле (не властивість, я виправлений) класу String. В основному різниця між вказівником та річчю, на яку він вказує. Якщо це не було прочитано лише ми, ми могли б змінити, на який екземпляр посилається Порожнє поле. - tvanfosson 3 лютого '09 о 17:07
Гаррі, не потрібно робити жодних досліджень. Подумай над цим. Рядок - це клас. Empty - це екземпляр String. - сенфо 3 лютого '09 о 17:12
Щось мені не зовсім зрозуміло: як на землі може статичний конструктор класу String створити екземпляр класу String? Це не якийсь сценарій "курка чи яйце"? - DrJokepu 3 лютого '09 о 17:12 5
Ця відповідь буде правильною майже для будь-якого іншого класу, крім System.String. .NET має багато спеціальних кожухів для рядків, і одна з них полягає в тому, що ви МОЖЕТЕ мати струнні константи, просто спробуйте. У цьому випадку Джефф Йейтс має правильну відповідь. - Джоель Мюллер 3 лютого '09 о 19:25
Як описано в §7.18, постійний вираз - це вираз, який можна повністю оцінити під час компіляції. Оскільки єдиним способом створення ненульового значення посилального типу, відмінного від рядка, є застосування нового оператора, а оскільки новий оператор не дозволений у постійному виразі, єдине можливе значення для констант типів посилань крім рядка є нульовим. Попередні два коментарі були взяті безпосередньо із специфікації мови C # і підтверджують те, що згадував Джоел Мюллер. - сенфо 4 лютого '09 о 15:05 5