Почему значение по умолчанию типа 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

NULL против пустого, когда работа с пользовательским вводом


вы также можете (начиная с 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 является ссылочным типом, а значение по умолчанию для ссылочного типа равно null.


может быть string ключевое слово смутило вас, так как оно выглядит точно так же, как и любое другое тип значения объявление, но на самом деле это псевдоним для System.String Как поясняется в этот вопрос.
Также темно-синий цвет в Visual Studio и строчная первая буква могут ввести в заблуждение, думая, что это struct.


Nullable типы не поступали до 2.0.

Если бы nullable типы были сделаны в начале языка, то строка была бы не-nullable и string? это было бы невозможно. Но они не могли сделать это для обратной совместимости.

многие люди говорят о ref-type или не ref type, но string является необычным классом, и решения были бы найдены, чтобы сделать это возможным.