У чому полягає суть рядка. Властивість порожнього


35

Чому майно було string foo = string.Emptyвключено до складу BCL? Це здається більш багатослівним і не зрозумілішим, ніж просто використання порожнього рядка ( string foo = "")


6
Нітпік: Це не частина мови. Він входить до складу BCL. VB.NET і F # можуть використовувати його, як і будь-яку іншу мову .NET.
Oded

19
Бо в іншому випадку ви не можете робити таких злих дій typeof(string).GetField("Empty").SetValue(null, " ");;)
Мейсон Уілер

1
@MasonWheeler - Радощі роздумів. Для справжнього зла вам потрібна самоаналіз, так?
Oded

1
@MasonWheeler, +1. О боже, окуляри, вони нічого не роблять!]
Мачадо

1
@MasonWheeler Це чисте, перегнане зло. Мені це подобається. Питання, якщо вас цікавить: чи не було б безпечніше (і пристойно виконати), як це написали public static string Empty { get { return string.Intern(""); } }?
Джессі К. Слікер

Відповіді:


55

Тут я можу тільки припустити:

string.Emptyбуло визначено для явності - при ініціалізації рядка може бути не зрозуміло з контексту, який ""насправді явно мався на увазі як ініціалізатор (замість того, щоб nullсказати " "або просто як власник місця під час тестування). Використання string.Empty- це однозначна відповідь на такий тип головоломки.

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

На відміну від того, що говорять інші про декілька об'єктів - це не проблема, оскільки будь-який літеральний рядок буде інтернований при компіляції. Сюди входить значення string.Empty- "". Щоразу, коли будь-яке з них повторюється в коді, об'єкт буде отриманий з пулу інтернів. Це вірно для домену додатка .


5
+1 за те, що поки є єдиною правильною відповіддю.
psr

Деякі мови можуть навіть не мати порожнього рядкового літералу. Мабуть, стандарт Паскаль цього не зробив.
dan04

2
"порожній рядок у C не є порожнім рядком" - але все-таки, якщо ви пишете "", ви отримуєте {'\0'}, так що між порожнім рядковим буквеним рядком і яким-небудь іншим способом обходу його визначення не було б різниці.
декрет

14

Я не на 100% впевнений у джерелах, з яких я це дізнався, але деякі моменти його використання включають:

  • Кожна рядок у складі .NET унікальна, тому є

    string foo = "";
    string bar = "";

    призводить до 2 рядків у вихідній збірці, оскільки рядки незмінні. Наявність обох посилань string.Emptyзменшує розмір збірки.

  • Явність. Коли ви зіткнетеся string.Emptyз наміром, зрозуміло, що це повинен бути порожній рядок. Але якщо ви зіткнулися foo = "", програміст видалив вміст рядка під час тестування і забув додати його назад, чи це має бути саме так?

1
Здавалося б, дивна поведінка для нього, щоб зберегти в пам’яті дві однакові нитки. Це насправді те, що робиться?
Ріг

36
Насправді робиться навпаки - це називається струнне інтернування (точніше, інтернування літералів). Я точно знаю, що це робиться на Java та Python, і я майже впевнений, що так і в мовах .NET. Звичайно, це може траплятися лише в межах однієї одиниці перекладу, тому, якщо динамічний завантажувач не об'єднає такі дані, ви можете отримати один порожній рядок на файл програми. Ще не дуже страшно.

9
@delnan абсолютно прав. ""/ string.Emptyінтерновані і буде створено лише один об’єкт.
Oded

11
@Andy - Все рядкові літерали інтерновані в .NET. Не всі струни. Програмно створені рядки не інтернуються за замовчуванням. Див. String.Intern на MSDN.
Oded

3
@ Oded та інше: насправді ніхто з вас не має правильного права. По-перше, літерали інтерновані в межах зборів, але не обов'язково в межах зборів . По-друге, незалежно від того, чи порожній рядок інтернований через складання, є деталлю реалізації; деякі версії CLR роблять, а деякі ні. В одній з інших відповідей є посилання на мою статтю про цей факт; дивіться його для деталей.
Ерік Ліпперт

2

Жоден об’єкт не буде створений для string.Empty. Використання ""створить об'єкт, який, швидше за все, вийде з пулу інтернів.

У минулому люди проводили тести і String.Emptyвиходили трохи швидше, але це мікрооптимізація.

Строка.Порожня це:

//The Empty constant holds the empty string value.   
//We need to call the String constructor so that the compiler doesn't mark 
//this as a literal.   
//Marking this as a literal would mean that it doesn't show up as a field 
//which we can access from native.  
public static readonly String Empty = ""; 

2
Отже, ваша думка ...?

1
Справа в String.Empty - це в основному константа для "". Знайдіть автора String.cs для глибшого значення. :)
Джон Рейнор

0

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

Якщо ви багато разів використовуєте один і той же рядок у вашій програмі, ви можете використовувати один і той же механізм, зателефонувавши String.Intern () зі своєю рядком. Але якщо ви використовуєте кожен рядок лише один раз, тоді ви будете використовувати лише більше пам'яті.

Тож String.Empty - це лише спеціальна оптимізація випадку, яку варто зробити для більшості застосунків .Net, тому вона була інтегрована в BCL.

Більш детально з цього приводу я настійно рекомендую ознайомитись із повідомленням у блозі Еріка Ліпперта .

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


4
Відповіді лише на посилання не дають хороших відповідей. Якщо Ерік коли-небудь реорганізує свій блог, ця відповідь стане марною. Будь ласка, підсумуйте публікацію тут, щоб ми мали всю інформацію.
ChrisF

7
@ChrisF: Я ніколи не можу реорганізувати блог. Це було б кардинальною зміною, і ви знаєте, як я ставлюсь до них.
Ерік Ліпперт

1
@EricLippert - Я розумію, що ти цього ніколи не робиш, однак відповіді лише на посилання - це не гарні відповіді, і нам потрібно заохочувати людей усвідомлювати це.
ChrisF

3
@EricLippert Йдеться не лише про ефемерні посилання. Йдеться також про ввічливість до читачів, у відповіді має бути принаймні достатньо вмісту, щоб читачі могли сформувати думку щодо того, чи слід переходити за посиланням. І відповідь має мати сенс навіть в офлайновій копії SE.
Жил "ТАК - перестань бути злим"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.