Почему значение по умолчанию типа строки 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Если кто-то передает вашу функцию anullсправочники, хотя.вот в чем дело -- каркас будет бросать
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 понятия "отсутствие значения", т. е. пустая строка и null, весь код, который потребляет эту функцию, должен будет выполнить 2 проверки. Один пустой, а другой-для нулевого.
короче говоря, всегда хорошо иметь только 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но вместо этого были пользовательские операции бокса и распаковки (которые будут преобразовываться в / из другого класса тип.) При таком подходе был бы класс типаNullableStringкоторый ведет себя как string делает сейчас, и пользовательский коробочный тип структурыString, который будет содержать одно частное полеValueтипаString. Попытка преобразоватьStringtoNullableStringили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.
типы с нулевым значением не появлялись до 2.0.
Если бы nullable типы были сделаны в начале языка, то строка была бы не nullable и string? это было бы ничтожно. Но они не могли сделать это для обратной совместимости.
многие люди говорят о ref-типе или не ref-типе, но string является необычным классом, и решения были бы найдены, чтобы сделать это возможным.
Comments