Почему значение по умолчанию типа string null вместо пустой строки?
это очень раздражает, чтобы проверить все мои строки null
прежде чем я смогу безопасно применять такие методы, как ToUpper()
, StartWith()
etc...
, если значение по умолчанию string
были бы пустой строкой, мне не пришлось бы тестировать, и я чувствовал бы, что это более согласуется с другими типами значений, такими как int
или double
например.
Кроме того,Nullable<String>
имело бы смысл.
так почему же дизайнеры C# решили использовать null
Как значение по умолчанию струны?
Примечание: это относится к этот вопрос, но больше сосредоточен на том, почему, а не что с ним делать.
14 ответов
почему значение по умолчанию типа строки null вместо пустого струна?
, потому что string
Это ссылка типа и значение по умолчанию для всех ссылочных типов составляет null
.
это очень раздражает, чтобы проверить все мои строки на null, прежде чем я могу безопасно применять такие методы, как ToUpper (), StartWith() и т. д...
, что согласуется с поведением ссылочных типов. Прежде чем ссылаться на их члены экземпляра, следует поставить чек на место для нулевой ссылки.
если бы значение по умолчанию string было пустой строкой, у меня бы не было чтобы проверить, и я чувствовал бы, что это более согласуется с другим например, типы значений, такие как int или double.
присвоение значения по умолчанию определенному ссылочному типу, отличному от null
бы непоследовательны.
дополнительно
Nullable<String>
сделали бы чувство.
Nullable<T>
работает с типами значений. Следует отметить тот факт, что Nullable
не было введено на оригинале платформа .NET таким образом, было бы много сломанного кода, если бы они изменили это правило.(вежливость @jcolebrand)
Хабиб прав-потому что string
является ссылочным типом.
но что более важно, вы не должны проверить на null
каждый раз, когда вы используете его. Вы, вероятно, должны бросить ArgumentNullException
Если кто-то передает вашу функцию a null
справочники, хотя.
вот в чем дело -- фреймворк бросит NullReferenceException
для вас в любом случае, если вы попытались позвонить .ToUpper()
на строку. Помните, что этот случай все еще может произойти, даже если вы проверите свои аргументы для null
поскольку любое свойство или метод объектов, переданных в вашу функцию в качестве параметров, могут оцениваться как null
.
это, как говорится, проверка пустых строк или нулей-обычная вещь, поэтому они предоставляют String.IsNullOrEmpty()
и String.IsNullOrWhiteSpace()
только для этой цели.
вы могли бы написать метод расширения (для чего это стоит):
public static string EmptyNull(this string str)
{
return str ?? "";
}
теперь это безопасно работает:
string str = null;
string upper = str.EmptyNull().ToUpper();
пустые строки и нули принципиально разные. Null-это отсутствие значения, а пустая строка-это пустое значение.
язык программирования, делающий предположения о "значении" переменной, в данном случае пустой строки, будет так же хорош, как инициализация строки с любым другим значением, которое не вызовет проблему нулевой ссылки.
кроме того, если вы передадите дескриптор этой строковой переменной в другие части приложения, то этот код будет нет способов проверки того, намеренно ли вы передали пустое значение или забыли заполнить значение этой переменной.
другой случай, когда это было бы проблемой, когда строка является возвращаемым значением из некоторой функции. Поскольку string является ссылочным типом и может технически иметь значение как null, так и empty, поэтому функция также может технически возвращать null или empty (нет ничего, чтобы остановить ее от этого). Теперь, поскольку есть 2 понятия "отсутствие ценности", i.e пустая строка и null, весь код, который потребляет эту функцию, должен будет выполнить 2 проверки. Один для пустого, а другой для null.
короче говоря, всегда хорошо иметь только 1 представление для одного состояния. Для более широкого обсуждения пустых и нулевых значений см. ссылки ниже.
https://softwareengineering.stackexchange.com/questions/32578/sql-empty-string-vs-null-value
вы также можете (начиная с VS2015 и нового компилятора) использовать следующее
string myString = null;
string result = myString?.ToUpper();
результат строки будет равен null.
из-за переменной строка ссылка, а не экземпляр.
инициализация его пустым по умолчанию было бы возможно, но это привело бы много несоответствий по всей доске.
Почему разработчики C# решили использовать null в качестве значения по умолчанию струны?
потому что строки ссылка типа, ссылочные типы по умолчанию имеют значение null
. Переменные ссылочных типов хранят ссылки на фактические данные.
давайте использовать default
ключевое слово для данного случая;
string str = default(string);
str
это string
, поэтому ссылка типа, так значение по умолчанию:null
.
int str = (default)(int);
str
это int
, поэтому тип значения, поэтому значение по умолчанию:zero
.
основная причина / проблема заключается в том, что разработчики спецификации CLS (которая определяет, как языки взаимодействуют с .net) не определили средство, с помощью которого члены класса могут указать, что они должны вызываться напрямую, а не через callvirt
, без вызывающего абонента, выполняющего проверку нулевой ссылки; и он не предоставил множество определяющих структур, которые не были бы подвержены "нормальному" боксу.
если бы спецификация CLS определила такое средство, то это было бы возможно для .net последовательно следовать примеру, установленному общей объектной моделью (COM), в соответствии с которой ссылка на нулевую строку считалась семантически эквивалентной пустой строке, а для других определяемых пользователем неизменяемых типов классов, которые должны иметь семантику значений, аналогично определять значения по умолчанию. По сути, то, что произойдет, будет для каждого члена String
, например,Length
будет написано что-то вроде [InvokableOnNull()] int String Length { get { if (this==null) return 0; else return _Length;} }
. Этот подход предложил бы очень хорошую семантику для вещей, которые должны вести себя как значения, но из-за проблем с реализацией необходимо хранить в куче. Самая большая трудность с этим подходом заключается в том, что семантика преобразования между такими типами и Object
может быть немного мутной.
альтернативным подходом было бы разрешить определение специальных типов структуры, которые не наследовались от Object
но вместо этого были пользовательские операции бокса и распаковки (которые будут преобразовываться в/из другого класса тип.) При таком подходе будет класс type NullableString
который ведет себя как string делает сейчас, и пользовательская структура типа String
, который будет содержать одно частное поле Value
типа String
. Попытка преобразовать String
to NullableString
или Object
вернутся Value
если не-null, или String.Empty
если значение null. Попытка бросить String
, а не-null ссылка на NullableString
экземпляр будет хранить ссылку в Value
(возможно, сохранение null, если длина равна нулю); литье любая другая ссылка вызовет исключение.
хотя строки должны храниться в куче, концептуально нет причин, по которым они не должны вести как типы значений, которые имеют ненулевое значение по умолчанию. Сохранение их как "нормальной" структуры, которая содержала бы ссылку, было бы эффективным для кода, который использовал их как тип "строка", но добавил бы дополнительный слой косвенности и неэффективности при приведении к "объекту". Пока я не предвидите, что .net добавит любую из вышеперечисленных функций в этот поздний срок, возможно, дизайнеры будущих фреймворков могут рассмотреть возможность их включения.
, если значение по умолчанию
string
будь пустая строка, мне не пришлось бы тестировать
неправильно! Изменение значения по умолчанию не изменяет тот факт, что это ссылочный тип, и кто-то все еще может явно set ссылки null
.
дополнительно
Nullable<String>
имело бы смысл.
настоящий момент. Было бы разумнее не позволять null
для любых ссылочных типов, а Nullable<TheRefType>
для данного объекта.
так почему же дизайнеры C# решили использовать
null
как значение по умолчанию строк?
согласованность с другими ссылочными типами. Теперь, зачем позволять null
в ссылочных типах вообще? Вероятно, так, что это похоже на C, хотя это сомнительное дизайнерское решение на языке, который также предоставляет Nullable
.
возможно, если бы вы использовали ??
оператор при назначении строковой переменной это может вам помочь.
string str = SomeMethodThatReturnsaString() ?? "";
// if SomeMethodThatReturnsaString() returns a null value, "" is assigned to str.
строка является неизменяемым объектом, что означает, что при заданном значении старое значение не стирается из памяти, а остается в старом месте, а новое значение помещается в новое место. Поэтому, если значение по умолчанию String a
был String.Empty
он будет тратить String.Empty
блок в памяти, когда ему было присвоено первое значение.
хотя это кажется незначительным, это может превратиться в проблему при инициализации большого массива строк со значениями по умолчанию String.Empty
. Конечно, вы могли бы всегда используйте изменяемый StringBuilder
класс, если это будет проблемой.
может быть string
ключевое слово смутило вас, так как оно выглядит точно так же, как и любое другое тип значения объявление, но на самом деле это псевдоним для System.String
Как поясняется в этот вопрос.
Также темно-синий цвет в Visual Studio и строчная первая буква могут ввести в заблуждение, думая, что это struct
.
Nullable типы не поступали до 2.0.
Если бы nullable типы были сделаны в начале языка, то строка была бы не-nullable и string? это было бы невозможно. Но они не могли сделать это для обратной совместимости.
многие люди говорят о ref-type или не ref type, но string является необычным классом, и решения были бы найдены, чтобы сделать это возможным.