Acho peculiar que você null.ToString()receba esse nome wtf. Por que isso te surpreende? Você não pode chamar um método de instância quando não tem nada para chamá-lo.
BoltClock
11
@BoltClock: Claro que é possível chamar um método de instância em uma instância nula. Simplesmente não é possível em C #, mas muito válida no CLR :)
leppie
1
As respostas em relação ao String.Concat estão quase corretas. De fato, o exemplo específico da pergunta é de dobragem constante , e os nulos na primeira linha são eliminados pelo compilador - ou seja, eles nunca são avaliados em tempo de execução porque não existem mais - o compilador os apagou. Eu escrevi um pequeno monólogo sobre todas as regras para concatenação e dobragem constante de Strings aqui para mais informações: stackoverflow.com/questions/9132338/… .
22630 Chris Shain
77
você não pode adicionar nada a uma string, mas não pode transformá-la em nada.
RGB
A segunda declaração não é válida? class null_extension { String ToString( Object this arg ) { return ToString(arg); } }
Nas operações de concatenação de cadeias, o compilador C # trata uma cadeia nula da mesma forma que uma cadeia vazia, mas não converte o valor da cadeia nula original.
O operador binário + executa concatenação de cadeia de caracteres quando um ou ambos os operandos são do tipo cadeia de caracteres.
Se um operando de concatenação de sequência for nulo, uma sequência vazia será substituída. Caso contrário, qualquer argumento não-string será convertido em sua representação de string chamando o ToStringmétodo virtual herdado do objeto de tipo.
Se ToStringretornar null, uma sequência vazia será substituída.
A razão do erro no segundo é:
null (Referência de C #) - A palavra-chave null é um literal que representa uma referência nula, que não se refere a nenhum objeto. null é o valor padrão das variáveis do tipo de referência.
Isso funcionaria então? var wtf = ((String)null).ToString();Estou trabalhando em Java recentemente, onde a conversão de nulos é possível, já faz um tempo desde que trabalhei com C #.
Jochem
14
@Jochem: Você ainda está tentando chamar um método em um objeto nulo, então acho que não. Pense nisso como null.ToString()vs ToString(null).
Svish
@ Skish sim, agora penso nisso novamente, é um objeto nulo, então você está certo, não vai funcionar. Também não seria em Java: exceção de ponteiro nulo. Deixa pra lá. Tnx para sua resposta! [edit: testou em Java: NullPointerException. Com a diferença de que com o elenco ele compila, sem o elenco não].
Jochem
geralmente não há motivo para concatenar intencionalmente ou ToString a palavra-chave nula. Se você precisar de uma string vazia, use string.Empty. se você precisar verificar se uma variável de cadeia é nula, use (myString == null) ou string.IsNullOrEmpty (myString). Alternativamente, para transformar uma variável de cadeia nula em string.Empty uso myNewString = (minhaString == null ?? string.Empty)
csauve
@Jochem lançando ele irá torná-lo compilar mas ele vai realmente lançar um NullReferenceException em tempo de execução
jeroenh
108
Como o +operador em C # traduz internamente para String.Concat, que é um método estático. E esse método é tratado nullcomo uma string vazia. Se você olhar a fonte do String.ConcatReflector, verá:
// while looping through the parameters
strArray[i]=(str ==null)?Empty: str;// then concatenate that string array
No entanto, não há + operador na classe String .. Então é o compilador traduzindo para String.Concat?
Superlogical
@ superlogical Sim, é isso que o compilador faz. Então, na verdade, o +operador em strings em C # é apenas açúcar sintático para String.Concat.
Botz3000
Além disso: o compilador seleciona automaticamente a sobrecarga do Concat que faz mais sentido. As sobrecargas disponíveis são 1, 2 ou 3 parâmetros de objeto, 4 parâmetros de objeto + __argliste uma paramsversão da matriz de objetos.
Wormbo
Qual array de strings está sendo modificado lá? Será Concatsempre criar uma nova matriz de strings não nulos, mesmo quando dado um array de strings não nulos, ou é outra coisa acontecendo?
Supercat
@supercat O array modificado é um novo array, que é passado para um método auxiliar privado. Você pode ver o código usando refletor.
precisa saber é o seguinte
29
A primeira amostra será traduzida para:
var bob =String.Concat("abc123",null,null,null,"abs123");
O Concatmétodo verifica a entrada e converte null como uma string vazia
A segunda amostra será traduzida para:
var wtf =((object)null).ToString();
Portanto, uma nullexceção de referência será gerada aqui
Na verdade, um AccessViolationExceptionserá lançada :)
leppie
Acabei de fazer :) ((object)null).ToString()=> AccessViolation((object)1 as string).ToString()=>NullReference
leppie
1
Eu tenho NullReferenceException. DN 4.0
Viacheslav Smityukh
Interessante. Quando eu coloco ((object)null).ToString()dentro de um try/catcheu NullReferenceExceptiontambém.
Leppie
3
@ Ieppie, exceto que não gera AccessViolation (por que seria?) - NullReferenceException aqui.
Jeroenh # 30/12
11
A primeira parte do seu código é tratada dessa maneira em String.Concat,
que é o que o compilador C # chama quando você adiciona strings. " abc" + nullé traduzido para String.Concat("abc", null),
e internamente, esse método substitui nullpor String.Empty. Portanto, é por isso que sua primeira parte do código não gera nenhuma exceção. é como
var bob ="abc"+string.Empty+string.Empty+string.Empty+"123";//abc123
E na segunda parte do seu código lança exceção porque 'null' não é um objeto, a palavra-chave null é um literal que representa uma referência nula , que não se refere a nenhum objeto. null é o valor padrão das variáveis do tipo de referência.
E ' ToString()' é um método que pode ser chamado por uma instância de um objeto, mas não por nenhum literal.
String.Emptynão é igual a null. É apenas tratado da mesma maneira em alguns métodos como String.Concat. Por exemplo, se você tiver uma variável de cadeia definida como nullC #, ela não será substituída por String.Emptyse você tentar chamar um método.
Botz3000
3
Quase. nullnão é tratado como String.Emptyem C #, é apenas tratado dessa maneira String.Concat, que é o que o compilador C # chama quando você adiciona strings. "abc" + nullé traduzido String.Concat("abc", null)e internamente esse método substitui nullpor String.Empty. A segunda parte está completamente correta.
Botz3000
9
Na estrutura COM que precedeu o .net, era necessário que qualquer rotina que recebesse uma sequência liberasse-a quando ela terminasse. Como era muito comum as seqüências de caracteres vazias serem passadas para dentro e fora das rotinas, e porque a tentativa de "liberar" um ponteiro nulo era definida como uma operação legítima do tipo nada, a Microsoft decidiu que um ponteiro de seqüência de caracteres nula representasse uma seqüência de caracteres vazia.
Para permitir alguma compatibilidade com o COM, muitas rotinas no .net interpretarão um objeto nulo como uma representação legal como uma seqüência de caracteres vazia. Com algumas pequenas alterações .net e seus idiomas (principalmente permitindo que os membros da instância indiquem "não invocam como virtuais"), a Microsoft poderia ter feito com que nullobjetos do tipo declarado String se comportassem ainda mais como cadeias vazias. Se a Microsoft tivesse feito isso, também teria que fazer o Nullable<T>trabalho de maneira um pouco diferente (para permitir - Nullable<String>algo que eles deveriam ter feito de qualquer maneira) - e / ou definir um NullableStringtipo que seria mais intercambiável String, mas que não consideraria um nullcomo uma sequência vazia válida.
Como é, há alguns contextos nos quais a nullserá considerado como uma string vazia legítima e outros nos quais não será. Não é uma situação terrivelmente útil, mas que os programadores devem conhecer. Em geral, as expressões do formulário stringValue.someMemberfalharão se stringValueestiverem null, mas a maioria dos métodos e operadores de estrutura que aceitam cadeias de caracteres como parâmetros considerarão nulluma cadeia vazia.
Realmente, é mais parecido var bob = Plus(Plus(Plus(Plus("abc",null),null),null),"123");. As sobrecargas do operador são métodos estáticos em seu coração: msdn.microsoft.com/en-us/library/s53ehcz3(v=VS.71).aspx Eles não eram var bob = null + "abc";ou , especialmente string bob = null + null;, não seriam válidos.
precisa
Você está certo, eu apenas senti que seria muito confuso se explicasse dessa maneira.
Nigel Thorne
3
Eu acho que porque é um literal que não se refere a nenhum objeto. ToString()precisa de um object.
Alguém disse neste tópico de discussão que você não pode criar uma string do nada.
(que é uma frase legal como eu acho). Mas sim - você pode :-), como mostra o exemplo a seguir:
var x =null+(string)null;var wtf = x.ToString();
funciona bem e não lança uma exceção. A única diferença é que você precisa converter um dos nulos em uma string - se você remover a string (string) , o exemplo ainda será compilado, mas lançará uma exceção em tempo de execução: "Operator '+' é ambíguo nos operandos de digite '<null>' e '<null>' ".
NB No exemplo de código acima, o valor de x não é nulo como você poderia esperar; na verdade, é uma sequência vazia depois de converter um dos operandos em uma sequência.
Outro fato interessante é que, em C # / .NET, a maneira como nullé tratada nem sempre é a mesma se você considerar diferentes tipos de dados. Por exemplo:
int? x =1;// string x = "1";
x = x +null+null;Console.WriteLine((x==null)?"<null>": x.ToString());
Considere a 1ª linha do trecho de código: se xfor uma variável inteira anulável (ou seja int?) que contém valor 1, você estará recebendo o resultado de <null>volta. Se for uma string (como mostrado no comentário) com valor "1", você estará "1"retornando em vez de <null>.
Nota: também interessante: se você estiver usando var x = 1;a primeira linha, receberá um erro de tempo de execução. Por quê? Porque a atribuição transformará a variável xno tipo de dados int, que não é anulável. O compilador não assume int?aqui e, portanto, falha na segunda linha em que nullé adicionado.
A adição nulla uma string é simplesmente ignorada. null(no seu segundo exemplo) não é uma instância de nenhum objeto, portanto nem sequer possui um ToString()método. É apenas um literal.
Porque não há diferença entre string.Emptye nullquando você concata seqüências de caracteres. Você também pode passar nulo para string.Format. Mas você está tentando chamar um método null, o que sempre resultaria em um NullReferenceExceptione, portanto, gera um erro do compilador.
Se, por algum motivo, você realmente quiser fazer isso, escreva um método de extensão que verifique nulle retorne string.Empty. Mas uma extensão como essa só deve ser usada quando for absolutamente necessária (na minha opinião).
Como geral: pode ou não ser válido aceitar nulo como parâmetro, dependendo da especificação, mas é sempre inválido chamar um método como nulo.
Esse é outro tópico do motivo pelo qual os operandos do operador + podem ser nulos no caso de strings. Isso é meio coisa de VB (desculpe pessoal) para facilitar a vida dos programadores, ou supondo que o programador não possa lidar com nulos. Eu discordo completamente desta especificação. 'desconhecido' + 'qualquer coisa' ainda deve ser 'desconhecido' ...
null.ToString()
receba esse nomewtf
. Por que isso te surpreende? Você não pode chamar um método de instância quando não tem nada para chamá-lo.class null_extension { String ToString( Object this arg ) { return ToString(arg); } }
Respostas:
O motivo do primeiro trabalho:
Do MSDN :
Mais informações sobre o operador binário + :
A razão do erro no segundo é:
null (Referência de C #) - A palavra-chave null é um literal que representa uma referência nula, que não se refere a nenhum objeto. null é o valor padrão das variáveis do tipo de referência.
fonte
wtf = ((String)null).ToString();
Estou trabalhando em Java recentemente, onde a conversão de nulos é possível, já faz um tempo desde que trabalhei com C #.null.ToString()
vsToString(null)
.Como o
+
operador em C # traduz internamente paraString.Concat
, que é um método estático. E esse método é tratadonull
como uma string vazia. Se você olhar a fonte doString.Concat
Reflector, verá:(O MSDN também menciona: http://msdn.microsoft.com/en-us/library/k9c94ey1.aspx )
Por outro lado,
ToString()
é um método de instância que você não pode chamarnull
(que tipo deve ser usadonull
?).fonte
+
operador em strings em C # é apenas açúcar sintático paraString.Concat
.__arglist
e umaparams
versão da matriz de objetos.Concat
sempre criar uma nova matriz de strings não nulos, mesmo quando dado um array de strings não nulos, ou é outra coisa acontecendo?A primeira amostra será traduzida para:
O
Concat
método verifica a entrada e converte null como uma string vaziaA segunda amostra será traduzida para:
Portanto, uma
null
exceção de referência será gerada aquifonte
AccessViolationException
será lançada :)((object)null).ToString()
=>AccessViolation
((object)1 as string).ToString()
=>NullReference
((object)null).ToString()
dentro de umtry/catch
euNullReferenceException
também.A primeira parte do seu código é tratada dessa maneira em
String.Concat
,que é o que o compilador C # chama quando você adiciona strings. "
abc" + null
é traduzido paraString.Concat("abc", null)
,e internamente, esse método substitui
null
porString.Empty
. Portanto, é por isso que sua primeira parte do código não gera nenhuma exceção. é comoE na segunda parte do seu código lança exceção porque 'null' não é um objeto, a palavra-chave null é um literal que representa uma referência nula , que não se refere a nenhum objeto. null é o valor padrão das variáveis do tipo de referência.
E '
ToString()
' é um método que pode ser chamado por uma instância de um objeto, mas não por nenhum literal.fonte
String.Empty
não é igual anull
. É apenas tratado da mesma maneira em alguns métodos comoString.Concat
. Por exemplo, se você tiver uma variável de cadeia definida comonull
C #, ela não será substituída porString.Empty
se você tentar chamar um método.null
não é tratado comoString.Empty
em C #, é apenas tratado dessa maneiraString.Concat
, que é o que o compilador C # chama quando você adiciona strings."abc" + null
é traduzidoString.Concat("abc", null)
e internamente esse método substituinull
porString.Empty
. A segunda parte está completamente correta.Na estrutura COM que precedeu o .net, era necessário que qualquer rotina que recebesse uma sequência liberasse-a quando ela terminasse. Como era muito comum as seqüências de caracteres vazias serem passadas para dentro e fora das rotinas, e porque a tentativa de "liberar" um ponteiro nulo era definida como uma operação legítima do tipo nada, a Microsoft decidiu que um ponteiro de seqüência de caracteres nula representasse uma seqüência de caracteres vazia.
Para permitir alguma compatibilidade com o COM, muitas rotinas no .net interpretarão um objeto nulo como uma representação legal como uma seqüência de caracteres vazia. Com algumas pequenas alterações .net e seus idiomas (principalmente permitindo que os membros da instância indiquem "não invocam como virtuais"), a Microsoft poderia ter feito com que
null
objetos do tipo declarado String se comportassem ainda mais como cadeias vazias. Se a Microsoft tivesse feito isso, também teria que fazer oNullable<T>
trabalho de maneira um pouco diferente (para permitir -Nullable<String>
algo que eles deveriam ter feito de qualquer maneira) - e / ou definir umNullableString
tipo que seria mais intercambiávelString
, mas que não consideraria umnull
como uma sequência vazia válida.Como é, há alguns contextos nos quais a
null
será considerado como uma string vazia legítima e outros nos quais não será. Não é uma situação terrivelmente útil, mas que os programadores devem conhecer. Em geral, as expressões do formuláriostringValue.someMember
falharão sestringValue
estiveremnull
, mas a maioria dos métodos e operadores de estrutura que aceitam cadeias de caracteres como parâmetros considerarãonull
uma cadeia vazia.fonte
'+'
é um operador infix. Como qualquer operador, está realmente chamando um método. Você pode imaginar uma versão não infix"wow".Plus(null) == "wow"
O implementador decidiu algo assim ...
Então .. seu exemplo se torna
que é o mesmo que
Em nenhum momento o null se torna uma string. Então
null.ToString()
não é diferente issonull.VoteMyAnswer()
. ;)fonte
var bob = Plus(Plus(Plus(Plus("abc",null),null),null),"123");
. As sobrecargas do operador são métodos estáticos em seu coração: msdn.microsoft.com/en-us/library/s53ehcz3(v=VS.71).aspx Eles não eramvar bob = null + "abc";
ou , especialmentestring bob = null + null;
, não seriam válidos.Eu acho que porque é um literal que não se refere a nenhum objeto.
ToString()
precisa de umobject
.fonte
Alguém disse neste tópico de discussão que você não pode criar uma string do nada. (que é uma frase legal como eu acho). Mas sim - você pode :-), como mostra o exemplo a seguir:
funciona bem e não lança uma exceção. A única diferença é que você precisa converter um dos nulos em uma string - se você remover a string (string) , o exemplo ainda será compilado, mas lançará uma exceção em tempo de execução: "Operator '+' é ambíguo nos operandos de digite '<null>' e '<null>' ".
NB No exemplo de código acima, o valor de x não é nulo como você poderia esperar; na verdade, é uma sequência vazia depois de converter um dos operandos em uma sequência.
Outro fato interessante é que, em C # / .NET, a maneira como
null
é tratada nem sempre é a mesma se você considerar diferentes tipos de dados. Por exemplo:Considere a 1ª linha do trecho de código: se
x
for uma variável inteira anulável (ou sejaint?
) que contém valor1
, você estará recebendo o resultado de<null>
volta. Se for uma string (como mostrado no comentário) com valor"1"
, você estará"1"
retornando em vez de<null>
.Nota: também interessante: se você estiver usando
var x = 1;
a primeira linha, receberá um erro de tempo de execução. Por quê? Porque a atribuição transformará a variávelx
no tipo de dadosint
, que não é anulável. O compilador não assumeint?
aqui e, portanto, falha na segunda linha em quenull
é adicionado.fonte
A adição
null
a uma string é simplesmente ignorada.null
(no seu segundo exemplo) não é uma instância de nenhum objeto, portanto nem sequer possui umToString()
método. É apenas um literal.fonte
Porque não há diferença entre
string.Empty
enull
quando você concata seqüências de caracteres. Você também pode passar nulo parastring.Format
. Mas você está tentando chamar um métodonull
, o que sempre resultaria em umNullReferenceException
e, portanto, gera um erro do compilador.Se, por algum motivo, você realmente quiser fazer isso, escreva um método de extensão que verifique
null
e retornestring.Empty
. Mas uma extensão como essa só deve ser usada quando for absolutamente necessária (na minha opinião).fonte
Como geral: pode ou não ser válido aceitar nulo como parâmetro, dependendo da especificação, mas é sempre inválido chamar um método como nulo.
Esse é outro tópico do motivo pelo qual os operandos do operador + podem ser nulos no caso de strings. Isso é meio coisa de VB (desculpe pessoal) para facilitar a vida dos programadores, ou supondo que o programador não possa lidar com nulos. Eu discordo completamente desta especificação. 'desconhecido' + 'qualquer coisa' ainda deve ser 'desconhecido' ...
fonte