Довольно неприятно проверять все мои строки, null
прежде чем я смогу безопасно применять такие методы, как ToUpper()
, и StartWith()
т.д ...
Если бы значением по умолчанию string
была пустая строка, мне не пришлось бы проверять ее, и я бы чувствовал, что она более соответствует другим типам значений, таким как int
или, double
например,. Дополнительно Nullable<String>
будет иметь смысл.
Так почему же разработчики C # решили использовать null
в качестве значения по умолчанию строки?
Примечание: это относится к этому вопросу , но больше сосредоточено на том, почему, а не что делать с ним.
c#
string
default-value
завивать волосы щипцами
источник
источник
null
(а также я рекомендую вам концептуально обрабатыватьnull
и очищать строки как разные вещи). Нулевое значение может быть результатом ошибки где-то, в то время как пустая строка должна передавать другое значение.Ответы:
Потому
string
что это ссылочный тип и значение по умолчанию для всех ссылочных типовnull
.Это согласуется с поведением ссылочных типов. Прежде чем вызывать членов их экземпляров, нужно установить проверку на нулевую ссылку.
Присвоение значения по умолчанию для определенного типа ссылки, кроме
null
сделал бы непоследовательным .Nullable<T>
работает с типами значений. Следует отметить тот факт, чтоNullable
он не был представлен на исходной платформе .NET, поэтому было бы много сломанного кода, если бы они изменили это правило ( Courtesy @jcolebrand ).источник
String
, за исключением того, что (1) поведение value-type-ish, имеющее пригодное для использования значение по умолчанию, и (2) неудачный дополнительный уровень косвенности бокса каждый раз, когда его приводят кObject
, Принимая во внимание, что представление кучиstring
уникально, наличие особой обработки, позволяющей избежать дополнительного бокса, не было бы большой натяжкой (на самом деле, возможность указать поведение бокса не по умолчанию было бы хорошо для других типов).Хабиб прав - потому что
string
это ссылочный тип.Но что более важно, вам не нужно проверять
null
каждый раз, когда вы используете его. Вы, вероятно, должны бросить,ArgumentNullException
если кто-то передает вашу функцию в качествеnull
ссылки.В том-то и дело, что фреймворк все равно бросил бы
NullReferenceException
вам, если бы вы попытались вызвать.ToUpper()
строку. Помните, что этот случай все еще может произойти, даже если вы проверяете свои аргументы,null
поскольку любое свойство или метод в объектах, передаваемых вашей функции в качестве параметров, может оцениватьсяnull
.При этом проверка на наличие пустых строк или нулей - обычное дело, поэтому они предоставляют
String.IsNullOrEmpty()
и именноString.IsNullOrWhiteSpace()
для этой цели.источник
NullReferenceException
себя ( msdn.microsoft.com/en-us/library/ms173163.aspx ); Вы бросаете,ArgumentNullException
если ваш метод не может принимать нулевые ссылки. Кроме того, NullRef, как правило, являются одним из наиболее сложных исключений для диагностики, когда вы исправляете проблемы, поэтому я не думаю, что рекомендация не проверять нулевое значение является очень хорошей.ArgumentNullException
имеет дополнительное преимущество, заключающееся в возможности указать имя параметра. Во время отладки это экономит ... ошибки, секунды. Но важные секунды.Вы можете написать метод расширения (для чего это стоит):
Теперь это работает безопасно:
источник
.EmptyNull()
, почему бы просто не использовать(str ?? "")
его там, где это необходимо? Тем не менее, я согласен с мнением, выраженным в комментарии @ DaveMarkle: вы, вероятно, не должны.null
иString.Empty
концептуально разные, и вы не можете относиться к одному так же, как к другому.Вы также можете использовать следующее, начиная с C # 6.0
Строка результата будет нулевой.
источник
public string Name { get; set; } = string.Empty;
Пустые строки и нули принципиально разные. Ноль - это отсутствие значения, а пустая строка - это пустое значение.
Язык программирования, делающий предположения о «значении» переменной, в данном случае пустой строки, будет так же хорош, как инициализация строки любым другим значением, которое не вызовет проблему нулевой ссылки.
Кроме того, если вы передадите дескриптор этой строковой переменной в другие части приложения, этот код не сможет проверить, преднамеренно ли вы передали пустое значение или вы забыли заполнить значение этой переменной.
Другой случай, когда это может быть проблемой, - когда строка является возвращаемым значением какой-либо функции. Поскольку string является ссылочным типом и технически может иметь значение как нулевое, так и пустое оба, поэтому функция также может технически возвращать нулевое или пустое значение (ничто не мешает ей сделать это). Теперь, поскольку существует 2 понятия «отсутствия значения», то есть пустая строка и ноль, весь код, потребляющий эту функцию, должен будет выполнить 2 проверки. Один для пустого, а другой для нулевого.
Короче говоря, всегда хорошо иметь только одно представление для одного государства. Для более широкого обсуждения пустых и нулевых значений, смотрите ссылки ниже.
/software/32578/sql-empty-string-vs-null-value
NULL vs Empty при работе с пользовательским вводом
источник
null
представлять пустую строку. Существует несколько способов, которыми .net мог бы реализовать аналогичную семантику, если бы они решили это сделать, особенно если учесть, что онString
имеет ряд характеристик, которые в любом случае делают его уникальным типом [например, он и два типа массива являются единственными типами, чье распределение размер не постоянен.Основная причина / проблема заключается в том, что разработчики спецификации 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
, который будет содержать одно закрытое полеValue
типаString
. Попытка преобразоватьString
вNullableString
илиObject
вернет,Value
если не ноль, илиString.Empty
если ноль. При попытке привести кString
ненулевой ссылке наNullableString
экземпляр будет сохранена ссылкаValue
(возможно, при сохранении нуля, если длина равна нулю); приведение любой другой ссылки вызовет исключение.Несмотря на то, что строки должны храниться в куче, концептуально нет причин, по которым они не должны вести себя как типы значений, которые имеют ненулевое значение по умолчанию. Хранение их в виде «нормальной» структуры, содержащей ссылку, было бы эффективно для кода, который использовал их как тип «строка», но добавил бы дополнительный уровень косвенности и неэффективности при приведении к «объекту». Хотя я не предполагаю, что .net добавит любую из перечисленных выше функций в более позднюю дату, возможно, разработчики будущих фреймворков могут рассмотреть возможность их включения.
источник
Nullable<>
, строки могут быть переопределены как типы значений; Я не могу говорить о затратах и преимуществах такого выбора.string
более эффективен, чемNullable<string>
был бы, необходимость использовать «более эффективный» метод более обременительна, чем возможность использовать тот же подход для всех значений базы данных обнуляемых данных.Поскольку строковая переменная является ссылкой , а не экземпляром .
Инициализация его по умолчанию для Empty была бы возможна, но это привело бы ко многим несоответствиям по всей доске.
источник
string
которой должен быть ссылочный тип. Конечно, фактические символы, составляющие строку, безусловно, должны храниться в куче, но, учитывая количество выделенной поддержки, которую строки уже имеют в CLR, не будет растяжкой иметьSystem.String
тип значения с одно закрытое полеValue
типаHeapString
. Это поле будет ссылочным типом и будет по умолчаниюnull
, ноString
структура, чьеValue
поле имеет значение null, будет вести себя как пустая строка. Единственным недостатком такого подхода было бы ...String
кObject
, при отсутствии кода особого случая во время выполнения приведет к созданию коробочногоString
экземпляра в куче, а не просто к копированию ссылки наHeapString
..Length
т. Д., Чтобы экземпляры, которые содержат пустая ссылка не будет пытаться разыменовать ее, а будет вести себя как подходящая для пустой строки. Будет ли Framework лучше или хуже сstring
реализованным таким образом, если кто-то хочетdefault(string)
быть пустой строкой ...string
оболочки типа значения для поля ссылочного типа было бы подходом, который требовал бы наименьшего количества изменений в других частях .net [действительно, если бы кто-то согласился принять преобразованиеString
дляObject
создания дополнительного элемента в штучной упаковке, можно просто иметьString
обыкновенную структуру с полем типа,Char[]
которое она никогда не выставляла]. Я думаю, что иметьHeapString
тип, вероятно, было бы лучше, но в некоторых отношениях строка типа значения, содержащая a,Char[]
была бы проще.Поскольку строки являются ссылочными типами , ссылочные типы имеют значение по умолчанию
null
. Переменные ссылочных типов хранят ссылки на фактические данные.Давайте использовать
default
ключевое слово для этого случая;str
этоstring
, так что это ссылочный тип , поэтому значение по умолчаниюnull
.str
являетсяint
, так что это тип значения , поэтому значение по умолчаниюzero
.источник
Неправильно! Изменение значения по умолчанию не меняет того факта, что это ссылочный тип, и кто-то может явно установить ссылку на
null
.Истинная точка зрения. Было бы больше смысла не разрешать
null
какие-либо ссылочные типы, вместо этого требуяNullable<TheRefType>
эту функцию.Согласованность с другими ссылочными типами. Теперь, зачем
null
вообще разрешать ссылочные типы? Вероятно, это похоже на C, хотя это сомнительное дизайнерское решение на языке, который также обеспечиваетNullable
.источник
Возможно, если вы будете использовать
??
оператор при назначении вашей строковой переменной, это может вам помочь.источник
String - это неизменный объект, который означает, что при задании значения старое значение не стирается из памяти, а остается в старом месте, а новое значение помещается в новое место. Таким образом, если значение по умолчанию
String a
былоString.Empty
, он потерял быString.Empty
блок в памяти, когда ему было дано его первое значение.Хотя это кажется незначительным, оно может превратиться в проблему при инициализации большого массива строк со значениями по умолчанию
String.Empty
. Конечно, вы всегда можете использовать изменяемыйStringBuilder
класс, если это будет проблемой.источник
String.Empty
. Я ошибаюсь?string
чтобы быть пустой строкой, состоит в том, чтобы разрешить все биты ноль как представление пустой строки. Есть несколько способов, которыми это может быть достигнуто, но я не думаю, что это связано с инициализацией ссылок наString.Empty
.String.Empty
или""
.string
хранения потребовало бы также изменения поведения инициализации всех структур или классов, имеющих поля типаstring
. Это было бы довольно большим изменением в дизайне .net, который в настоящее время ожидает инициализации нуля любого типа, даже не задумываясь о том, что это такое, за исключением только его общего размера.Поскольку строка является ссылочным типом, а значение по умолчанию для ссылочного типа является нулевым.
источник
Возможно,
string
ключевое слово смутило вас, так как оно выглядит точно так же, как любое другое объявление типа значения , но на самом деле это псевдоним,System.String
как описано в этом вопросе .Кроме того, темно-синий цвет в Visual Studio и первая строчная буква могут ввести в заблуждение, считая, что это
struct
.источник
object
ключевого слова? Хотя по общему признанию, это используется гораздо меньше, чемstring
.int
псевдоним дляSystem.Int32
. В чем ваша точка зрения? :)System.Int32
является ,Struct
таким образом , имея значение по умолчанию , в то время какSystem.String
это ,Class
имеющий указатель со значением по умолчаниюnull
. Они визуально представлены в том же шрифте / цвете. Без знания можно думать, что они действуют одинаково (= имея значение по умолчанию). Мой ответ был написан на основе идеи когнитивной психологии en.wikipedia.org/wiki/Cognitive_psychology :-)Обнуляемые типы не появлялись до 2.0.
Если бы в начале языка были сделаны обнуляемые типы, то строка была бы не обнуляемой, а строка? был бы обнуляемым. Но они не могли сделать это из-за обратной совместимости.
Многие люди говорят о типе ref или не типе ref, но string - это необычный класс, и были бы найдены решения, позволяющие сделать это возможным.
источник