Не можна використовувати String.Empty як значення за замовчуванням для необов’язкового параметра


89

Я читаю Ефективний C # Білла Вагнера. У пункті 14 - Зменшити логіку повторюваної ініціалізації він показує наступний приклад використання нових додаткових параметрів у конструкторі:

public MyClass(int initialCount = 0, string name = "")

Зверніть увагу, що він використовував ""замість string.Empty.
Він коментує:

Ви зауважите [у прикладі вище], що другий конструктор вказав "" значення за замовчуванням для параметра name , а не більш звичний string.Empty. Це тому string.Empty, що не є константою часу компіляції. Це статична властивість, визначена в класі рядків. Оскільки це не константа компіляції, ви не можете використовувати її як значення за замовчуванням для параметра.

Якщо ми не можемо використовувати string.Emptyстатику в будь-яких ситуаціях, то чи не перешкоджає це її цілі? Я думав, що ми скористаємося цим, щоб переконатися, що у нас є незалежні від системи засоби посилання на порожній рядок. Моє розуміння неправильне? Дякую.

ОНОВЛЕННЯ
Просто наступний коментар. За даними MSDN:

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

Тоді ми не зможемо використовувати System.Environment.NewLineні те, ні інше, але інстанційовані об’єкти як значення за замовчуванням. Я ще не використовував VS2010, і це розчаровує!


2
Мені невідомі будь-які відмінності між тим, як порожні рядки представлені на різних платформах. Це не як новий рядок.
Tom Cabanski

Правильно, я про це думав, то чи не просто це виглядає приємніше в коді?
Mikeyg36,

1
CLR, а не "Система", є визначальним фактором щодо того, чи є "" порожнім рядком чи ні. Тому я думаю, ви можете спокійно припустити, що "" є незалежним від системи способом посилання на рядок у відповідній реалізації CLR.
Кріс Тейлор,

"незалежний від системи"? е-е, на відміну від системного ""? (???)
Кверті

Відповідно до MSDN: Значенням цього поля є рядок нульової довжини, "". тож, очевидно, це не має нічого спільного з незалежністю платформи, на що вказують багато людей. Проте все ще здається, що люди насправді не знають, навіщо його використовувати!
Mikeyg36,

Відповіді:


65

Що стосується компілятора C # 2.0, то тут і так мало сенсу String.Empty, і насправді в багатьох випадках це песимізація, оскільки компілятор може вбудувати деякі посилання на, ""але не може зробити те саме String.Empty.

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


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

Дякую за роз'яснення. Я оглянувся і не знайшов хорошого резюме змін у C # 2.0, хоча впевнений, що прочитав його раніше. Я знайшов відповідь StackOverflow від 2008 року з деякими посиланнями на додаткову технічну інформацію. stackoverflow.com/questions/151472/…
Енді Мортімер,

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

14
Я виявив, що набагато простіше швидко ідентифікувати порожній рядок із String.Empty, ніж два рази переглядати "", щоб переконатись, що в ньому немає апострофа або чогось подібного. +1 для пояснення.
NotMe

11
+1 Кріс. Також у VS ви насправді не можете здійснити пошук за звичками "" (крім стандартного пошуку, який також поверне всі текстові збіги, включаючи коментарі та розмітку). Ви можете здійснити пошук за кодовим використанням за допомогою string.Empty.
MutantNinjaCodeMonkey

53

Ніщо не заважає вам визначити власну константу для порожнього рядка, якщо ви дійсно хочете використовувати її як необов’язкове значення параметра:

const string String_Empty = "";

public static void PrintString(string s = String_Empty)
{
    Console.WriteLine(s);
}

[Окрім того, однією з причин, щоб віддавати перевагу String.Emptyнад ""загалом, про яку не згадувалося в інших відповідях, є те, що існують різні символи Unicode (столяри нульової ширини тощо), які фактично непомітні неозброєним оком. Отже, те, що виглядає "", не обов’язково порожній рядок, тоді як String.Emptyви точно знаєте, що використовуєте. Я усвідомлюю, що це не поширене джерело помилок, але це можливо.]


2
Також є невидимі символи ідентифікатора, тому щось, що виглядає як String_Empty, не обов'язково. Стандарт Unicode має переважно ігнорований розділ з питань безпеки.
Jim Balter

25

З вихідного питання:

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

Яким чином порожній рядок може відрізнятися від системи до системи? Це завжди рядок без символів! Мені б дуже було страшно, якщо я коли-небудь знайду реалізацію, де string.Empty == ""повернуто false :) Це не те саме, що щось на зразок Environment.NewLine.

З повідомлення про нагороду у боротьбі з терористом:

Я хочу String.Empty можна використовувати як параметр за замовчуванням у наступному випуску C #. : D

Ну цього точно не станеться.

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

З string.Emptyцим насправді безглуздо - використання ""зробить те, що ти хочеш; це що боляче використовувати строковий літерал? (Я використовую буквал скрізь - я ніколи не використовуюstring.Empty - але це інший аргумент.)

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

public void RecordTime(string message, DateTime? dateTime = null)
{
    var realDateTime = dateTime ?? DateTime.UtcNow;
}

... але це не завжди доречно.

На закінчення:

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

Це насправді хороший спосіб вирішення проблеми. Те саме можна використовувати для перенесення / встановлення інших залежних від пристрою змінних, таких як Environment.Newline.. Єдине, чого не вистачає у вашому прикладі, це перевірка змінної на наявність null та повернення винятку назад розробнику, який повідомляє йому, що, хоча він має нульовий характер, не приймається. if(dateTime == null){ throw new ArgumentException("The dateTime parameter must be set. Nullable type used for device independent variable set.");}або щось подібне. Але мені це дуже подобається! Будь-які інші застереження, щоб зробити це по-своєму?
MaxOvrdrv

@MaxOvrdrv: Ви не хочете, щоб значення null було помилкою - вся справа в тому, що коли воно має значення null, ви обчислюєте за замовчуванням. Застереження полягає в тому, що він не дозволяє передавати null як дійсне значення саме по собі.
Джон Скіт,

Ви в цьому абсолютно праві. Моє ліжко. - І так, це було б єдиним справжнім застереженням, чи не так ... це не так вже й погано. Ще раз: мені дуже подобається це рішення! :) Дякуємо за розміщення! :)
MaxOvrdrv

7

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


2
Можливо, це заважає заплутати ""і " ", але я не можу сказати, що " "це все таке загальне.
Грег

8
Я б запропонував кожному, хто не може визначити різницю між цими потребами, або кращі окуляри, або зменшити роздільну здатність свого екрану. У мене поганий зір, і я не пам’ятаю, щоб коли-небудь робив цю помилку (і мені доводиться працювати з великою кількістю коду, який містить обидва ці фактори).
Ганс Олссон,

2
string.Empty корисний для з’ясування точного наміру програміста. "" нічого не розповідає про намір, що, якби намір програміста був ініціалізувати змінну, як ця "лол", але забув ... у цьому випадку є безмежні можливості та рядок, Порожній зручний і робить кращу роботу
кориснийБе

4

Думаю, ідея рядка. Порожня - це покращує читабельність. Це не як новий рядок, де існує якась різниця між тим, як він представлений на різних платформах. Погано, його не можна використовувати як параметр за замовчуванням. Однак це не спричинить жодних проблем, якщо ви портуєте між Windows і чимось на зразок Mono в Linux.


5
Я думаю, ви, мабуть, праві, що справа в тому, що деякі люди вважають String.Emptyбільш читабельними. . . хоча особисто я думаю, що це трохи горіхово. ""це, мабуть, найпоширеніший рядок, який всі бачили мільярд разів, то як це не читається? String.Emptyє приблизно настільки ж корисним, ніби існував файл Int32.Zero.
Тім Гудман,

3

Як FYI, схоже, на значення, передані конструкторам атрибутів, накладається одне і те ж обмеження - вони повинні бути постійними. Оскільки string.empty визначається як:

public static readonly string Empty

замість фактичної константи, її не можна використовувати.


1

я використовую string.Empty суто для читабельності.

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

Наприклад:

if(someString == string.Empty)
{

}

проти

if(someString == "")
{

}

Перше ifтвердження просто здається мені набагато обдуманішим і читабельнішим. Оскільки це лише вподобання, я справді не бачу, щоб поїзд-розбивач мав використовувати ""замість цього string.Empty.


-2

Можливо, найкращим рішенням цієї проблеми є перевантаження цього методу таким чином:

public static void PrintString() 
{ 
    PrintString(string.Empty);
}

3
Як це відповісти на вищезазначене питання?
Пранав Сінгх

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