Мне кажется странным, что тебе null.ToString()дали имя wtf. Почему это вас удивляет? Вы не можете вызвать метод экземпляра, если вам не из чего его вызывать.
BoltClock
11
@BoltClock: Конечно, можно вызвать метод экземпляра для нулевого экземпляра. Просто невозможно в C #, но очень актуально в CLR :)
leppie
1
Ответы на String.Concat почти правильные. Фактически, конкретный пример в вопросе - это пример сворачивания констант , и нули в первой строке удаляются компилятором, т.е. они никогда не оцениваются во время выполнения, потому что они больше не существуют - компилятор стер их. Я написал небольшой монолог обо всех правилах конкатенации и константного сворачивания строк здесь для получения дополнительной информации: stackoverflow.com/questions/9132338/… .
Крис Шейн
77
вы не можете ничего добавить к строке, но вы не можете сделать строку из ничего.
RGB
Второе утверждение неверно? class null_extension { String ToString( Object this arg ) { return ToString(arg); } }
Бинарный оператор + выполняет конкатенацию строк, если один или оба операнда относятся к строковому типу.
Если операнд конкатенации строк равен нулю, подставляется пустая строка. В противном случае любой нестроковый аргумент преобразуется в его строковое представление путем вызова виртуального ToStringметода, унаследованного от объекта типа.
Если ToStringвозвращается null, подставляется пустая строка.
Причина ошибки в секундах:
null (справочник C #) - ключевое слово null - это литерал, представляющий пустую ссылку, не относящуюся ни к какому объекту. null - это значение по умолчанию для переменных ссылочного типа.
Тогда это сработает? var wtf = ((String)null).ToString();Я недавно работаю на Java, где возможно приведение null, прошло некоторое время с тех пор, как я работал с C #.
Jochem
14
@Jochem: Вы все еще пытаетесь вызвать метод для нулевого объекта, поэтому я предполагаю, что нет. Думайте об этом как null.ToString()против ToString(null).
Свиш
@Svish да, теперь я снова думаю об этом, это нулевой объект, так что вы правы, это не сработает. Этого не было бы и в Java: исключение нулевого указателя. Неважно. Спасибо за ответ! [изменить: протестировал его на Java: NullPointerException. С той разницей, что с приведением он компилируется, а без приведения - нет].
Jochem
обычно нет причин для намеренного объединения или ToString ключевого слова null. Если вам нужна пустая строка, используйте string.Empty. если вам нужно проверить, имеет ли строковая переменная значение null, вы можете использовать (myString == null) или string.IsNullOrEmpty (myString). В качестве альтернативы для преобразования нулевой строковой переменной в string.Empty используйте myNewString = (myString == null ?? string.Empty)
csauve
Приведение @Jochem заставит его скомпилировать, но действительно вызовет исключение NullReferenceException во время выполнения
jeroenh
108
Поскольку +оператор в C # выполняет внутреннее преобразование в String.Concatстатический метод. И этот метод обрабатывается nullкак пустая строка. Если вы посмотрите на исходный код String.Concatв Reflector, вы увидите:
// while looping through the parameters
strArray[i]=(str ==null)?Empty: str;// then concatenate that string array
Однако в классе String нет оператора + .. Так это компилятор переводит на String.Concat?
superlogical
@superlogical Да, это то, что делает компилятор. Так что на самом деле +оператор для строк в C # - это просто синтаксический сахар для String.Concat.
Botz3000
В дополнение к этому: компилятор автоматически выбирает наиболее подходящую перегрузку Concat. Доступные перегрузки: 1, 2 или 3 параметра объекта, 4 параметра объекта + __arglistи paramsверсия массива объектов.
Wormbo
Какой массив строк там модифицируется? ConcatВсегда ли создается новый массив ненулевых строк, даже если задан массив ненулевых строк, или происходит что-то еще?
supercat 09
@supercat Модифицированный массив - это новый массив, который затем передается частному вспомогательному методу. Вы можете сами посмотреть код с помощью рефлектора.
Botz3000
29
Первый образец будет переведен на:
var bob =String.Concat("abc123",null,null,null,"abs123");
ConcatВходной метод проверки и перевести нуль как пустая строка
Второй образец будет переведен на:
var wtf =((object)null).ToString();
Таким образом, здесь nullбудет сгенерировано ссылочное исключение
Я только что сделал :) ((object)null).ToString()=> AccessViolation((object)1 as string).ToString()=>NullReference
leppie
1
У меня есть исключение NullReferenceException. DN 4.0
Вячеслав Смитюх
Интересный. Когда я вставляю ((object)null).ToString()внутрь, try/catchя NullReferenceExceptionтоже получаю .
leppie
3
@Ieppie, за исключением того, что он тоже не генерирует AccessViolation (зачем?) - NullReferenceException здесь.
jeroenh
11
Первая часть вашего кода обрабатывается так же, как в String.Concat,
это то, что компилятор C # вызывает при добавлении строк. " abc" + nullпереводится на String.Concat("abc", null),
а внутри этот метод заменяется nullна String.Empty. Вот почему ваша первая часть кода не вызывает никаких исключений. это просто как
var bob ="abc"+string.Empty+string.Empty+string.Empty+"123";//abc123
И во 2-й части вашего кода выдается исключение, потому что «null» не является объектом, ключевое слово null - это литерал, представляющий пустую ссылку , которая не ссылается ни на какой объект. null - это значение по умолчанию для переменных ссылочного типа.
И " ToString()" - это метод, который может быть вызван экземпляром объекта, но не любым литералом.
String.Emptyне равно null. Это просто обрабатывается таким же образом в некоторых методах, таких как String.Concat. Например, если у вас установлена строковая переменная null, C # не заменит ее, String.Emptyесли вы попытаетесь вызвать для нее метод.
Botz3000
3
Почти. nullне обрабатывается так, как String.EmptyC #, он просто обрабатывается так же, как это происходит в String.Concatкомпиляторе C #, когда вы добавляете строки. "abc" + nullпреобразуется в String.Concat("abc", null), и внутренне этот метод заменяется nullна String.Empty. Вторая часть полностью верна.
Botz3000
9
В структуре COM, предшествовавшей .NET, для любой подпрограммы, получившей строку, было необходимо освободить ее, когда она будет с ней выполнена. Поскольку пустые строки очень часто передавались в подпрограммы и из них, и поскольку попытка «освободить» нулевой указатель была определена как законная операция, не выполняющая никаких действий, Microsoft решила, что указатель нулевой строки представляет собой пустую строку.
Чтобы обеспечить некоторую совместимость с COM, многие подпрограммы в .net будут интерпретировать нулевой объект как законное представление как пустую строку. С парой небольших изменений .net и его языков (в первую очередь, позволяя членам экземпляра указывать «не вызывать как виртуальный»), Microsoft могла бы заставить nullобъекты объявленного типа String вести себя даже больше как пустые строки. Если бы Microsoft сделала это, ей также пришлось бы Nullable<T>работать несколько иначе (чтобы разрешить - Nullable<String>то, что они должны были сделать в любом случае, ИМХО) и / или определить NullableStringтип, который был бы в основном взаимозаменяемым String, но который не учитывал бы nullкак допустимая пустая строка.
Как бы то ни было, есть некоторые контексты, в которых a nullбудет рассматриваться как допустимая пустая строка, а в других - нет. Не очень полезная ситуация, но программисты должны знать о ней. Как правило, выражения формы stringValue.someMemberне работают, если они stringValueесть null, но большинство методов и операторов инфраструктуры, которые принимают строки в качестве параметров, будут рассматриваться nullкак пустая строка.
На самом деле это больше похоже var bob = Plus(Plus(Plus(Plus("abc",null),null),null),"123");. В основе перегрузки операторов лежат статические методы: msdn.microsoft.com/en-us/library/s53ehcz3(v=VS.71).aspx Если бы они не были var bob = null + "abc";или были string bob = null + null;бы недопустимыми.
Бен Мошер
Вы правы, я просто почувствовал, что буду слишком запутан, если объясню это так.
Найджел Торн
3
Я думаю, потому что это литерал, который не относится ни к какому объекту. ToString()нужен object.
Кто-то сказал в этой ветке обсуждения, что вы не можете сделать строку из ничего.
(что, на мой взгляд, хорошая фраза). Но да - вы можете :-), как показывает следующий пример:
var x =null+(string)null;var wtf = x.ToString();
отлично работает и вообще не вызывает исключения. Единственное отличие состоит в том, что вам нужно преобразовать один из нулей в строку - если вы удалите приведение (string) , то пример все равно компилируется, но выдает исключение времени выполнения: «Оператор '+' неоднозначен для операндов введите '<null>' и '<null>' ".
NB. В приведенном выше примере кода значение x не равно нулю, как вы могли ожидать, это фактически пустая строка после преобразования одного из операндов в строку.
Другой интересный факт заключается в том, что в C # / .NET способ nullобработки не всегда одинаков, если рассматривать разные типы данных. Например:
int? x =1;// string x = "1";
x = x +null+null;Console.WriteLine((x==null)?"<null>": x.ToString());
Что касается 1-й строки фрагмента кода: если xэто целочисленная переменная, допускающая значение NULL (т. Е. int?), Содержащая значение 1, то вы получаете результат <null>обратно. Если это строка (как показано в комментарии) со значением "1", то вы "1"скорее возвращаетесь, чем <null>.
NB Также интересно: если вы используете var x = 1;для первой строки, вы получаете ошибку времени выполнения. Зачем? Поскольку присвоение превратит переменную xв тип данных int, который не допускает значения NULL. Компилятор здесь не предполагает int?, и, следовательно, не работает во второй строке, где nullдобавлено.
Добавление nullв строку просто игнорируется. null(в вашем втором примере) не является экземпляром какого-либо объекта, поэтому у него даже нет ToString()метода. Это просто буквально.
Потому что нет разницы между string.Emptyи, nullкогда вы объединяете строки. Вы также можете передать null string.Format. Но вы пытаетесь вызвать метод null, который всегда приводит к NullReferenceExceptionвозникновению ошибки компилятора.
Если по какой-то причине вы действительно хотите это сделать, вы можете написать метод расширения, который проверяет, nullа затем возвращает string.Empty. Но такое расширение следует использовать только в случае крайней необходимости (на мой взгляд).
В общем: это может быть или не быть допустимым, принимая значение null в качестве параметра в зависимости от спецификации, но всегда недопустимо вызывать метод для null.
Это и другая тема, почему операнды оператора + могут быть нулевыми в случае строк. Это что-то вроде VB (извините, ребята), чтобы облегчить жизнь программистам, или предположим, что программист не может иметь дело с нулями. Я полностью не согласен с этой спецификацией. "unknown" + "something" должно оставаться "unknown" ...
null.ToString()
дали имяwtf
. Почему это вас удивляет? Вы не можете вызвать метод экземпляра, если вам не из чего его вызывать.class null_extension { String ToString( Object this arg ) { return ToString(arg); } }
Ответы:
Причина первой работы:
Из MSDN :
Дополнительная информация о бинарном операторе + :
Причина ошибки в секундах:
null (справочник C #) - ключевое слово null - это литерал, представляющий пустую ссылку, не относящуюся ни к какому объекту. null - это значение по умолчанию для переменных ссылочного типа.
источник
wtf = ((String)null).ToString();
Я недавно работаю на Java, где возможно приведение null, прошло некоторое время с тех пор, как я работал с C #.null.ToString()
противToString(null)
.Поскольку
+
оператор в C # выполняет внутреннее преобразование вString.Concat
статический метод. И этот метод обрабатываетсяnull
как пустая строка. Если вы посмотрите на исходный кодString.Concat
в Reflector, вы увидите:(MSDN тоже упоминает об этом: http://msdn.microsoft.com/en-us/library/k9c94ey1.aspx )
С другой стороны,
ToString()
это метод экземпляра, который нельзя вызватьnull
(для какого типа следует использоватьnull
?).источник
+
оператор для строк в C # - это просто синтаксический сахар дляString.Concat
.__arglist
иparams
версия массива объектов.Concat
Всегда ли создается новый массив ненулевых строк, даже если задан массив ненулевых строк, или происходит что-то еще?Первый образец будет переведен на:
Concat
Входной метод проверки и перевести нуль как пустая строкаВторой образец будет переведен на:
Таким образом, здесь
null
будет сгенерировано ссылочное исключениеисточник
AccessViolationException
будет брошено :)((object)null).ToString()
=>AccessViolation
((object)1 as string).ToString()
=>NullReference
((object)null).ToString()
внутрь,try/catch
яNullReferenceException
тоже получаю .Первая часть вашего кода обрабатывается так же, как в
String.Concat
,это то, что компилятор C # вызывает при добавлении строк. "
abc" + null
переводится наString.Concat("abc", null)
,а внутри этот метод заменяется
null
наString.Empty
. Вот почему ваша первая часть кода не вызывает никаких исключений. это просто какИ во 2-й части вашего кода выдается исключение, потому что «null» не является объектом, ключевое слово null - это литерал, представляющий пустую ссылку , которая не ссылается ни на какой объект. null - это значение по умолчанию для переменных ссылочного типа.
И "
ToString()
" - это метод, который может быть вызван экземпляром объекта, но не любым литералом.источник
String.Empty
не равноnull
. Это просто обрабатывается таким же образом в некоторых методах, таких какString.Concat
. Например, если у вас установлена строковая переменнаяnull
, C # не заменит ее,String.Empty
если вы попытаетесь вызвать для нее метод.null
не обрабатывается так, какString.Empty
C #, он просто обрабатывается так же, как это происходит вString.Concat
компиляторе C #, когда вы добавляете строки."abc" + null
преобразуется вString.Concat("abc", null)
, и внутренне этот метод заменяетсяnull
наString.Empty
. Вторая часть полностью верна.В структуре COM, предшествовавшей .NET, для любой подпрограммы, получившей строку, было необходимо освободить ее, когда она будет с ней выполнена. Поскольку пустые строки очень часто передавались в подпрограммы и из них, и поскольку попытка «освободить» нулевой указатель была определена как законная операция, не выполняющая никаких действий, Microsoft решила, что указатель нулевой строки представляет собой пустую строку.
Чтобы обеспечить некоторую совместимость с COM, многие подпрограммы в .net будут интерпретировать нулевой объект как законное представление как пустую строку. С парой небольших изменений .net и его языков (в первую очередь, позволяя членам экземпляра указывать «не вызывать как виртуальный»), Microsoft могла бы заставить
null
объекты объявленного типа String вести себя даже больше как пустые строки. Если бы Microsoft сделала это, ей также пришлось быNullable<T>
работать несколько иначе (чтобы разрешить -Nullable<String>
то, что они должны были сделать в любом случае, ИМХО) и / или определитьNullableString
тип, который был бы в основном взаимозаменяемымString
, но который не учитывал быnull
как допустимая пустая строка.Как бы то ни было, есть некоторые контексты, в которых a
null
будет рассматриваться как допустимая пустая строка, а в других - нет. Не очень полезная ситуация, но программисты должны знать о ней. Как правило, выражения формыstringValue.someMember
не работают, если ониstringValue
естьnull
, но большинство методов и операторов инфраструктуры, которые принимают строки в качестве параметров, будут рассматриватьсяnull
как пустая строка.источник
'+'
- инфиксный оператор. Как и любой оператор, он действительно вызывает метод. Вы можете представить себе неинфиксную версию"wow".Plus(null) == "wow"
Примерно так решил исполнитель ...
Итак .. ваш пример становится
который совпадает с
Ни в коем случае значение null не становится строкой. Так
null.ToString()
что ничем не отличаетсяnull.VoteMyAnswer()
. ;)источник
var bob = Plus(Plus(Plus(Plus("abc",null),null),null),"123");
. В основе перегрузки операторов лежат статические методы: msdn.microsoft.com/en-us/library/s53ehcz3(v=VS.71).aspx Если бы они не былиvar bob = null + "abc";
или былиstring bob = null + null;
бы недопустимыми.Я думаю, потому что это литерал, который не относится ни к какому объекту.
ToString()
нуженobject
.источник
Кто-то сказал в этой ветке обсуждения, что вы не можете сделать строку из ничего. (что, на мой взгляд, хорошая фраза). Но да - вы можете :-), как показывает следующий пример:
отлично работает и вообще не вызывает исключения. Единственное отличие состоит в том, что вам нужно преобразовать один из нулей в строку - если вы удалите приведение (string) , то пример все равно компилируется, но выдает исключение времени выполнения: «Оператор '+' неоднозначен для операндов введите '<null>' и '<null>' ".
NB. В приведенном выше примере кода значение x не равно нулю, как вы могли ожидать, это фактически пустая строка после преобразования одного из операндов в строку.
Другой интересный факт заключается в том, что в C # / .NET способ
null
обработки не всегда одинаков, если рассматривать разные типы данных. Например:Что касается 1-й строки фрагмента кода: если
x
это целочисленная переменная, допускающая значение NULL (т. Е.int?
), Содержащая значение1
, то вы получаете результат<null>
обратно. Если это строка (как показано в комментарии) со значением"1"
, то вы"1"
скорее возвращаетесь, чем<null>
.NB Также интересно: если вы используете
var x = 1;
для первой строки, вы получаете ошибку времени выполнения. Зачем? Поскольку присвоение превратит переменнуюx
в тип данныхint
, который не допускает значения NULL. Компилятор здесь не предполагаетint?
, и, следовательно, не работает во второй строке, гдеnull
добавлено.источник
Добавление
null
в строку просто игнорируется.null
(в вашем втором примере) не является экземпляром какого-либо объекта, поэтому у него даже нетToString()
метода. Это просто буквально.источник
Потому что нет разницы между
string.Empty
и,null
когда вы объединяете строки. Вы также можете передать nullstring.Format
. Но вы пытаетесь вызвать методnull
, который всегда приводит кNullReferenceException
возникновению ошибки компилятора.Если по какой-то причине вы действительно хотите это сделать, вы можете написать метод расширения, который проверяет,
null
а затем возвращаетstring.Empty
. Но такое расширение следует использовать только в случае крайней необходимости (на мой взгляд).источник
В общем: это может быть или не быть допустимым, принимая значение null в качестве параметра в зависимости от спецификации, но всегда недопустимо вызывать метод для null.
Это и другая тема, почему операнды оператора + могут быть нулевыми в случае строк. Это что-то вроде VB (извините, ребята), чтобы облегчить жизнь программистам, или предположим, что программист не может иметь дело с нулями. Я полностью не согласен с этой спецификацией. "unknown" + "something" должно оставаться "unknown" ...
источник