Инициализация строки по умолчанию: NULL или Empty? [закрыто]

130

Я всегда инициализировал свои строки значением NULL, полагая, что NULL означает отсутствие значения, а "" или String.Empty является допустимым значением. В последнее время я видел больше примеров кода, где String.Empty считается значением по умолчанию или не представляет никакого значения. Это кажется мне странным: с новыми добавленными в C # типами, допускающими значение NULL, кажется, что мы делаем шаг назад со строками, не используя NULL для представления «Нет значения».

Что вы используете в качестве инициализатора по умолчанию и почему?

Изменить: на основе ответов я продолжаю свои дальнейшие мысли

  1. Как избежать обработки ошибок Если значение не должно быть нулевым, почему оно было установлено NULLв первую очередь? Может быть, было бы лучше идентифицировать ошибку в том месте, где она возникает, а не скрывать ее в остальной части вашей кодовой базы?

  2. Избегание нулевых проверок Если вы устали выполнять нулевые проверки в коде, не лучше ли абстрагироваться от нулевых проверок? Возможно, обернуть (или расширить!) Строковые методы, чтобы сделать их NULLбезопасными? Что произойдет, если вы постоянно используете, String.Emptyа в вашу систему сработает нуль, вы все равно начнете добавлять NULLпроверки?

Не могу не вернуться к мнению, что это лень. Любой администратор баз данных дал бы вам девять глупостей, если бы вы использовали '' вместо nullего \ ее базы данных. Я думаю, что те же принципы применимы и в программировании, и должен быть кто-то, кто ударил бы по голове тех, кто использует, String.Emptyа не NULLпредставляет никакой ценности.

Смежные вопросы

vfilby
источник
«Разумный»? Не должна быть Дана, которую я знаю.
vfilby 05
@Joel, я поражен тем, сколько людей понятия не имеют о Зиме или GIR. Я также поражен тем, что некоторые из моих друзей находят это отталкивающим. Я не говорю, что это чистая добро, но в этом есть потрясающие самородки юмора.
vfilby 05
Я знаю, но иногда забавно притвориться иначе.
Dana the Sane
1
Я часто сталкиваюсь с этой проблемой в коллекциях форм MVC или переменных сеанса, я обнаружил, что наиболее полезным было преобразование null в String.Empty с помощью ?? сокращенно, а затем примените любую требуемую строковую операцию. например. (item ?? String.Empty) .Trim (). ToUpper ()
sonjz
4
это не конструктивно ??
nawfal

Ответы:

111

+1 за различение между пустым и пустым. Я согласен с тем, что «пустой» должен означать «действительный, но пустой», а «NULL» должен означать «недействительный».

Поэтому я бы ответил на ваш вопрос так:

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

NULL, если это ошибка, если последующий код не устанавливает значение явно.

Адам Лисс
источник
11
Отличить NULL от пустого - это здорово, когда между ними есть разница. Однако есть много случаев, когда нет различий, и поэтому наличие двух способов представления одного и того же является помехой.
Грег Смалтер
6
@Greg: Хотя я согласен с тем, что разнообразие может вызвать путаницу, оно также может быть большим преимуществом. Простое и последовательное соглашение о написании "" или NULL для различения действительных и недопустимых значений облегчит понимание вашего кода. Вот почему я всегда тестирую логические значения с помощью if (var), указатели с if (var! = NULL) и целые числа с if (var! = 0) - все они означают одно и то же для компилятора, но они несут дополнительную информацию, которая помогает бедному разработчику, обслуживающему мой код.
Адам Лисс
32

По данным MSDN :

Инициализируя строки Emptyзначением вместо null, вы можете снизить вероятность NullReferenceExceptionвозникновения.

IsNullOrEmpty()Тем не менее, всегда использовать - это хорошая практика.

Томалак
источник
45
Тот факт, что вы уменьшаете вероятность исключения, не означает, что исключения не должно происходить. Если ваш код зависит от значения, он должен вызвать исключение!
rmeador 05
1
Конечно, здесь нет аргументов. OTOH, если вы просто складываете строки вместе ... Я думаю, это зависит от стиля кодирования, опыта и ситуации.
Tomalak
Это в основном то, что я использую, различать, что также использовать.
PositiveGuy
3
Не забывайте IsNullOrWhiteSpace () для .NET framework 4+
Coops
13

Почему вы вообще хотите, чтобы ваша строка инициализировалась? Вам не нужно инициализировать переменную, когда вы ее объявляете, и IMO, вы должны делать это только тогда, когда значение, которое вы присваиваете, является допустимым в контексте блока кода.

Я это часто вижу:

string name = null; // or String.Empty
if (condition)
{
  name = "foo";
}
else
{
  name = "bar";
}

return name;

Не инициализировать значение null было бы столь же эффективно. Более того, чаще всего вам нужно присвоить значение. Инициализируя значение null, вы потенциально можете пропустить пути кода, которым не присваивается значение. Вот так:

string name = null; // or String.Empty
if (condition)
{
  name = "foo";
}
else if (othercondition)
{
  name = "bar";
}

return name; //returns null when condition and othercondition are false

Если вы не инициализируете значение null, компилятор выдаст ошибку, сообщающую, что не все пути кода присваивают значение. Конечно, это очень простой пример ...

Matthijs


источник
В Visual Studio, которую, как я полагаю, использует почти каждый программист на C #, ваша вторая ситуация (без символа = null) будет генерировать предупреждение именно по той причине, которую вы указали - не имеет значения, является ли значение строки по умолчанию нулевым. если вы не гарантируете присвоение через каждый путь кода, IDE (и / или я полагаю, что базовый компилятор [?]) выдаст предупреждение. Хотя предупреждения не препятствуют компиляции, они все еще существуют - оставление тех, которые легко решаются, может помочь запутать других, которые могут потребовать внимания программиста
Code Jockey
насколько мне известно, первая ситуация будет вполне удовлетворительной без инициализации nameto null(без предупреждений), потому что каждый путь кода присваивает значение name- нет необходимости инициализировать там вообще
Code Jockey
8

Для большинства программ, которые на самом деле не являются программами для обработки строк, логика программы не должна зависеть от содержимого строковых переменных. Каждый раз, когда я вижу что-то подобное в программе:

if (s == "value")

У меня плохое предчувствие. Почему в этом методе есть строковый литерал? Что за настройка s? Знает ли он, что логика зависит от значения строки? Он знает, что для работы он должен быть строчными? Должен ли я исправить это, изменив его на использование String.Compare? Должен ли я создавать Enumи разбирать его?

С этой точки зрения философия кода довольно проста: вы по возможности избегаете проверки содержимого строки. Сравнение строки с String.Emptyдействительно просто частным случаем сравнения ее с литералом: этого следует избегать, если только в этом нет необходимости.

Зная это, я не моргаю, когда вижу что-то вроде этого в нашей базе кода:

string msg = Validate(item);
if (msg != null)
{
   DisplayErrorMessage(msg);
   return;
}

Я знаю, что Validateэто никогда не вернется String.Empty, потому что мы пишем лучший код, чем этот.

Конечно, в остальном мире так не работает. Когда ваша программа имеет дело с пользовательским вводом, базами данных, файлами и т. Д., Вы должны учитывать другие философии. Вот и задача вашего кода - навести порядок в хаосе. Часть этого порядка - знать, когда должна означать пустая строка, String.Emptyа когда - null.

(Чтобы убедиться, что я не говорю из своей задницы, я просто искал в нашей кодовой базе `String.IsNullOrEmpty '. Все 54 его вхождения находятся в методах, которые обрабатывают ввод пользователя, возвращают значения из скриптов Python, исследуют значения, полученные из внешние API и т. д.)

Роберт Россни
источник
6

На самом деле это зияющая дыра в языке C #. Невозможно определить строку, которая не может быть нулевой. Это вызывает такие простые проблемы, как та, которую вы описываете, что заставляет программистов принимать решение, которое им не нужно принимать, поскольку во многих случаях NULL и String.Empty означают одно и то же. Это, в свою очередь, может позже вынудить других программистов обрабатывать как NULL, так и String.Empty, что раздражает.

Более серьезная проблема заключается в том, что базы данных позволяют вам определять поля, которые сопоставляются со строкой C #, но поля базы данных могут быть определены как NOT NULL. Таким образом, невозможно точно представить, скажем, поле varchar (100) NOT NULL в SQL Server с использованием типа C #.

Другие языки, такие как Spec #, позволяют это.

На мой взгляд, неспособность C # определить строку, не допускающую null, так же плоха, как и его предыдущая неспособность определить int, которая допускает null.

Чтобы полностью ответить на ваш вопрос: я всегда использую пустую строку для инициализации по умолчанию, потому что она больше похожа на то, как работают типы данных базы данных. (Изменить: этот оператор был очень неясным. Он должен был гласить: «Я использую пустую строку для инициализации по умолчанию, когда NULL является избыточным состоянием, почти так же, как я установил столбец базы данных как NOT NULL, если NULL был бы лишним состоянием. , многие из моих столбцов БД настроены как NOT NULL, поэтому, когда я помещаю их в строку C #, строка будет пустой или иметь значение, но никогда не будет NULL. Другими словами, я только инициализирую строку NULL if null имеет значение, отличное от значения String.Empty, и я считаю, что этот случай менее распространен (но здесь люди привели законные примеры этого случая). ")

Грег Смалтер
источник
Использование String.Empty похоже только на один из способов определения строки базы данных. Использование null для представления отсутствия значения гораздо более согласованно с пустым nvarchar. Я думаю, что любой достойный администратор баз данных дал бы вам девять глупостей, если бы вы использовали '', чтобы не представлять никакой ценности.
vfilby
На самом деле, Грег, ты все неправильно понял. Типы значений, не допускающие значения NULL, в наименьшей степени «как работают типы базы данных», потому что они никогда не могут содержать значение NULL и, следовательно, не могут отображаться в столбец, допускающий значение NULL. В контракте любая строка может отображаться в любой столбец varchar.
Tor Haugen
Вы правы, мое последнее утверждение было недостаточно ясным. В большинстве случаев столбцы моей базы данных НЕ НУЛЕНЫ (потому что не было бы никакой разницы между значением пустой строки и NULL), поэтому я пытаюсь сохранить одинаковые строки, никогда не сохраняя в них null, и именно это я имел в виду.
Грег Смалтер
5

Это зависит.

Вам нужно знать, отсутствует ли значение (возможно ли, чтобы оно не было определено)?

Является ли пустая строка допустимым значением для использования этой строки?

Если вы ответили «да» на оба вопроса, тогда вы захотите использовать null. В противном случае вы не сможете отличить «без значения» от «пустой строки».

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

Herms
источник
3

Я либо устанавливаю его на "", либо на null - я всегда проверяю с помощью String.IsNullOrEmpty, так что все в порядке.

Но внутренний компьютерщик во мне говорит, что я должен установить для него значение null, прежде чем я получу для него правильное значение ...

Хирургический кодер
источник
3

Я всегда объявляю строку с помощью string.empty;

Эрвин Тер
источник
2

Возможно ли, что это метод предотвращения ошибок (желательно или нет ..)? Поскольку "" по-прежнему является строкой, вы могли бы вызывать для нее строковые функции, что привело бы к исключению, если бы оно было NULL?

Дана вменяемая
источник
1
Это оправдание, которое я обычно слышу, просто звучит как лень. «Я не хочу утруждать себя проверкой этого значения, поэтому я воспользуюсь ярлыком», - вот как мне кажется.
vfilby 05
Да, я не возражаю. Могут быть некоторые ситуации, когда уменьшение количества кода проверки ошибок - это хорошо, но вызовы функций, которые не имеют никакого эффекта, тоже не самые лучшие ...
Дана Разумная
2

Я всегда инициализирую их как NULL.

Я всегда использую, string.IsNullOrEmpty(someString)чтобы проверить его ценность.

Просто.

Pure.Krome
источник
1

Это зависит от ситуации. В большинстве случаев я использую String.Empty, потому что не хочу выполнять нулевые проверки каждый раз, когда пытаюсь использовать строку. Это значительно упрощает код и снижает вероятность нежелательных сбоев NullReferenceException.

Я устанавливаю для строки значение null только тогда, когда мне нужно знать, была ли она установлена ​​или нет, и где пустая строка является чем-то допустимым для ее установки. На практике я нахожу такие ситуации редкими.

Роб Проуз
источник
1

Пустая строка - это значение (кусок текста, который, кстати, не содержит букв). Null означает отсутствие ценности.

Я инициализирую переменные нулевым значением, когда хочу указать, что они не указывают на фактические значения и не содержат их - когда намерение не имеет значения.

yfeldblum
источник
1

Повторяя ответ Томалака, имейте в виду, что когда вы присваиваете строковой переменной начальное значение null, ваша переменная больше не является строковым объектом; то же самое с любым объектом в C #. Итак, если вы попытаетесь получить доступ к любым методам или свойствам для своей переменной и предполагаете, что это строковый объект, вы получите исключение NullReferenceException.

Майкл Ритчсон
источник
1

Null следует использовать только в тех случаях, когда значение не является обязательным. Если значение не является необязательным (например, «Имя» или «Адрес»), оно никогда не должно быть нулевым. Это относится к базам данных, а также к POCO и пользовательскому интерфейсу. Null означает, что «это значение является необязательным и в настоящее время отсутствует».

Если ваше поле не является необязательным, вы должны инициализировать его как пустую строку. Чтобы инициализировать его как null, ваш объект перейдет в недопустимое состояние (недопустимое для вашей собственной модели данных).

Лично я предпочел бы, чтобы строки не допускали значения NULL по умолчанию, а вместо этого допускали бы значение NULL только в том случае, если мы объявим «строку?». Хотя, возможно, это невозможно или логично на более глубоком уровне; Точно сказать не могу.

Дейв Кузино
источник
0

Строки не являются типами значений и никогда ими не будут ;-)

Тор Хауген
источник
0

Я думаю, что нет причин не использовать null для неназначенного (или в этом месте в потоке программы) значения. Если хотите различать, там == null. Если вы просто хотите проверить определенное значение и вас не волнует, является ли оно нулевым или другим, String.Equals ("XXX", MyStringVar) прекрасно подойдет.

Volker
источник