Me parece curioso que null.ToString()se le dé el nombre wtf. ¿Por qué te sorprende eso? No puede llamar a un método de instancia cuando no tiene nada para llamarlo en primer lugar.
BoltClock
11
@BoltClock: Por supuesto, es posible llamar a un método de instancia en una instancia nula. Simplemente no es posible en C #, pero es muy válido en CLR :)
leppie
1
Las respuestas con respecto a String.Concat son casi correctas. De hecho, el ejemplo específico en la pregunta es uno de plegado constante , y el compilador elimina los valores nulos en la primera línea, es decir, nunca se evalúan en tiempo de ejecución porque ya no existen, el compilador los ha borrado. Escribí un pequeño monólogo sobre todas las reglas para la concatenación y el plegado constante de cadenas aquí para obtener más información: stackoverflow.com/questions/9132338/… .
Chris Shain
77
no puede agregar nada a una cadena pero no puede hacer una cadena de la nada.
RGB
¿La segunda declaración no es válida? class null_extension { String ToString( Object this arg ) { return ToString(arg); } }
En las operaciones de concatenación de cadenas, el compilador de C # trata una cadena nula igual que una cadena vacía, pero no convierte el valor de la cadena nula original.
El operador binario + realiza la concatenación de cadenas cuando uno o ambos operandos son de tipo cadena.
Si un operando de concatenación de cadenas es nulo, se sustituye una cadena vacía. De lo contrario, cualquier argumento que no sea de cadena se convierte en su representación de cadena invocando el ToStringmétodo virtual heredado del objeto de tipo.
Si se ToStringdevuelve null, se sustituye una cadena vacía.
La razón del error en segundo es:
nulo (referencia de C #) : la palabra clave nula es un literal que representa una referencia nula, una que no hace referencia a ningún objeto. nulo es el valor predeterminado de las variables de tipo de referencia.
¿Funcionaría entonces? var wtf = ((String)null).ToString();Estoy trabajando en Java recientemente, donde es posible lanzar nulos, ha pasado un tiempo desde que trabajé con C #.
Jochem
14
@Jochem: Todavía estás intentando llamar a un método en un objeto nulo, así que supongo que no. Piense en ello como null.ToString()vs ToString(null).
Svish
@Svish sí, ahora lo pienso de nuevo, es un objeto nulo, así que tienes razón, no funcionará. Tampoco en Java: excepción de puntero nulo. No importa. Tnx por tu respuesta! [edit: probado en Java: NullPointerException. Con la diferencia de que con el elenco compila, sin el elenco no lo hace].
Jochem
generalmente no hay razón para concatenar intencionalmente o ToString la palabra clave nula. Si necesita una cadena vacía, use string.Empty. si necesita verificar si una variable de cadena es nula, puede usar (myString == null) o string.IsNullOrEmpty (myString). Alternativamente para transformar una variable de cadena nula en cadena. Vacío use myNewString = (myString == null ?? string.Empty)
csauve
El lanzamiento de @Jochem lo hará compilar, pero de hecho arrojará una NullReferenceException en tiempo de ejecución
jeroenh
108
Porque el +operador en C # se traduce internamente en String.Concat, que es un método estático. Y este método pasa a tratarse nullcomo una cadena vacía. Si miras la fuente de String.ConcatReflector, lo verás:
// while looping through the parameters
strArray[i]=(str ==null)?Empty: str;// then concatenate that string array
Sin embargo, no hay un operador + en la clase String. Entonces, ¿es el compilador que se traduce a String.Concat?
superlogical
@superlogical Sí, eso es lo que hace el compilador. Entonces, en realidad, el +operador en cadenas en C # es solo azúcar sintáctico para String.Concat.
Botz3000
Además de eso: el compilador selecciona automáticamente la sobrecarga de Concat que tiene más sentido. Las sobrecargas disponibles son 1, 2 o 3 parámetros de objeto, 4 parámetros de objeto + __arglisty una paramsversión de matriz de objetos.
Wormbo
¿Qué conjunto de cadenas se está modificando allí? ¿ ConcatSiempre crea una nueva matriz de cadenas no nulas, incluso cuando se le da una matriz de cadenas no nulas, o está sucediendo algo más?
supercat
@supercat La matriz modificada es una nueva matriz, que luego se pasa a un método auxiliar privado. Puede mirar el código usted mismo usando el reflector.
Botz3000
29
La primera muestra se traducirá a:
var bob =String.Concat("abc123",null,null,null,"abs123");
El Concatmétodo verifica la entrada y traduce nulo como una cadena vacía
La segunda muestra se traducirá a:
var wtf =((object)null).ToString();
Entonces nullse generará una excepción de referencia aquí
En realidad, se AccessViolationExceptionlanzará un :) :)
leppie
Acabo de hacerlo :) ((object)null).ToString()=> AccessViolation((object)1 as string).ToString()=>NullReference
leppie
1
Tengo NullReferenceException. DN 4.0
Viacheslav Smityukh
Interesante. Cuando me meto ((object)null).ToString()dentro de un try/catchme sale NullReferenceExceptiontambién.
leppie
3
@Ieppie, excepto que tampoco arroja AccessViolation (¿por qué lo haría?) - NullReferenceException aquí.
jeroenh
11
La primera parte de su código se trata así en String.Concat,
que es lo que llama el compilador de C # cuando agrega cadenas. " abc" + nullse traduce a String.Concat("abc", null),
e internamente, ese método reemplaza nullcon String.Empty. Por eso, su primera parte del código no arroja ninguna excepción. es como
var bob ="abc"+string.Empty+string.Empty+string.Empty+"123";//abc123
Y en la segunda parte de su código arroja una excepción porque 'nulo' no es un objeto, la palabra clave nula es un literal que representa una referencia nula , una que no hace referencia a ningún objeto. nulo es el valor predeterminado de las variables de tipo de referencia.
Y ' ToString()' es un método que puede ser llamado por una instancia de un objeto pero no por un literal.
String.Emptyno es igual a null. Simplemente se trata de la misma manera en algunos métodos como String.Concat. Por ejemplo, si tiene una variable de cadena establecida en null, C # no la reemplazará String.Emptysi intenta llamar a un método.
Botz3000
3
Casi. nullno es tratado como String.Emptypor C #, solo es tratado así String.Concat, que es lo que llama el compilador de C # cuando agrega cadenas. "abc" + nullse traduce String.Concat("abc", null)e internamente ese método reemplaza nullcon String.Empty. La segunda parte es completamente correcta.
Botz3000
9
En el marco COM que precedió a .net, era necesario que cualquier rutina que recibiera una cadena lo liberara cuando terminara. Debido a que era muy común que las cadenas vacías se pasaran dentro y fuera de las rutinas, y porque el intento de "liberar" un puntero nulo se definía como una operación legítima de no hacer nada, Microsoft decidió que un puntero de cadena nula representara una cadena vacía.
Para permitir cierta compatibilidad con COM, muchas rutinas en .net interpretarán un objeto nulo como una representación legal como una cadena vacía. Con un par de cambios leves .net y sus idiomas (lo que permite que los miembros de la instancia indiquen "no invocar como virtual"), Microsoft podría haber hecho que los nullobjetos de tipo declarado String se comporten aún más como cadenas vacías. Si Microsoft hubiera hecho eso, también habría tenido que hacer que el Nullable<T>trabajo fuera algo diferente (para permitir, Nullable<String>algo que deberían haber hecho en mi humilde opinión de todos modos) y / o definir un NullableStringtipo que sería en su mayoría intercambiable String, pero que no consideraría un nullcomo una cadena vacía válida.
Tal como están las cosas, hay algunos contextos en los que a nullse considerará una cadena vacía legítima y otros en los que no. No es una situación terriblemente útil, pero una que los programadores deben tener en cuenta. En general, las expresiones del formulario stringValue.someMemberfallarán si stringValuees así null, pero la mayoría de los métodos y operadores de marco que aceptan cadenas como parámetros se considerarán nullcomo una cadena vacía.
'+'es un operador infijo. Como cualquier operador, realmente está llamando a un método. Podrías imaginar una versión no infija"wow".Plus(null) == "wow"
Realmente, es más como var bob = Plus(Plus(Plus(Plus("abc",null),null),null),"123");. Las sobrecargas de los operadores son métodos estáticos en su esencia: msdn.microsoft.com/en-us/library/s53ehcz3(v=VS.71).aspx Si no lo fueran, var bob = null + "abc";o especialmente string bob = null + null;no serían válidos.
Ben Mosher
Tienes razón, sentí que sería demasiado confuso si lo explicara de esa manera.
Nigel Thorne
3
Supongo que porque es un literal que no se refiere a ningún objeto. ToString()necesita un object.
Alguien dijo en este hilo de discusión que no se puede hacer una cadena de la nada.
(que es una bonita frase como creo). Pero sí, puedes :-), como muestra el siguiente ejemplo:
var x =null+(string)null;var wtf = x.ToString();
funciona bien y no arroja una excepción en absoluto. La única diferencia es que debe convertir uno de los valores nulos en una cadena: si elimina la conversión (cadena) , el ejemplo aún se compila, pero arroja una excepción en tiempo de ejecución: "Operador '+' es ambiguo en operandos de escriba '<nulo>' y '<nulo>' ".
Nota: en el ejemplo de código anterior, el valor de x no es nulo como podría esperarse, en realidad es una cadena vacía después de haber convertido uno de los operandos en una cadena.
Otro hecho interesante es que en C # / .NET la forma en que nullse trata no siempre es la misma si se consideran diferentes tipos de datos. Por ejemplo:
int? x =1;// string x = "1";
x = x +null+null;Console.WriteLine((x==null)?"<null>": x.ToString());
Con respecto a la primera línea del fragmento de código: si xes una variable entera anulable (es decir, que int?contiene un valor) 1, está obteniendo el resultado <null>. Si es una cadena (como se muestra en el comentario) con valor "1", entonces está "1"regresando en lugar de hacerlo <null>.
Nota: también es interesante: si está utilizando var x = 1;la primera línea, obtendrá un error de tiempo de ejecución. ¿Por qué? Debido a que la asignación convertirá la variable xen el tipo de datos int, que no es anulable. El compilador no asume int?aquí, y por lo tanto falla en la segunda línea donde nullse agrega.
Agregar nulla una cadena simplemente se ignora. null(en su segundo ejemplo) no es una instancia de ningún objeto, por lo que ni siquiera tiene un ToString()método. Es solo un literal.
Porque no hay diferencia entre string.Emptyy nullcuando concatene cadenas. Puede pasar nulo string.Formattambién. Pero está intentando llamar a un método null, que siempre daría como resultado NullReferenceExceptionay, por lo tanto, genera un error de compilación.
Si por alguna razón realmente desea hacerlo, puede escribir un método de extensión, que verifica nully luego regresa string.Empty. Pero una extensión como esa solo debería usarse cuando sea absolutamente necesario (en mi opinión).
Como general: puede o no ser válido aceptar nulo como parámetro dependiendo de la especificación, pero siempre es inválido llamar a un método en nulo.
Ese es otro tema por el cual los operandos del operador + pueden ser nulos en el caso de cadenas. Esto es algo de VB (lo siento chicos) para facilitar la vida de los programadores, o suponiendo que el programador no pueda lidiar con los valores nulos. Estoy completamente en desacuerdo con esta especificación. 'desconocido' + 'cualquier cosa' debería seguir siendo 'desconocido' ...
null.ToString()
se le dé el nombrewtf
. ¿Por qué te sorprende eso? No puede llamar a un método de instancia cuando no tiene nada para llamarlo en primer lugar.class null_extension { String ToString( Object this arg ) { return ToString(arg); } }
Respuestas:
El motivo del primer trabajo:
De MSDN :
Más información sobre el operador binario + :
La razón del error en segundo es:
nulo (referencia de C #) : la palabra clave nula es un literal que representa una referencia nula, una que no hace referencia a ningún objeto. nulo es el valor predeterminado de las variables de tipo de referencia.
fuente
wtf = ((String)null).ToString();
Estoy trabajando en Java recientemente, donde es posible lanzar nulos, ha pasado un tiempo desde que trabajé con C #.null.ToString()
vsToString(null)
.Porque el
+
operador en C # se traduce internamente enString.Concat
, que es un método estático. Y este método pasa a tratarsenull
como una cadena vacía. Si miras la fuente deString.Concat
Reflector, lo verás:(MSDN también lo menciona: http://msdn.microsoft.com/en-us/library/k9c94ey1.aspx )
Por otro lado,
ToString()
es un método de instancia, al que no puede recurrirnull
(¿para qué tipo debe usarsenull
?).fuente
+
operador en cadenas en C # es solo azúcar sintáctico paraString.Concat
.__arglist
y unaparams
versión de matriz de objetos.Concat
Siempre crea una nueva matriz de cadenas no nulas, incluso cuando se le da una matriz de cadenas no nulas, o está sucediendo algo más?La primera muestra se traducirá a:
El
Concat
método verifica la entrada y traduce nulo como una cadena vacíaLa segunda muestra se traducirá a:
Entonces
null
se generará una excepción de referencia aquífuente
AccessViolationException
lanzará un :) :)((object)null).ToString()
=>AccessViolation
((object)1 as string).ToString()
=>NullReference
((object)null).ToString()
dentro de untry/catch
me saleNullReferenceException
también.La primera parte de su código se trata así en
String.Concat
,que es lo que llama el compilador de C # cuando agrega cadenas. "
abc" + null
se traduce aString.Concat("abc", null)
,e internamente, ese método reemplaza
null
conString.Empty
. Por eso, su primera parte del código no arroja ninguna excepción. es comoY en la segunda parte de su código arroja una excepción porque 'nulo' no es un objeto, la palabra clave nula es un literal que representa una referencia nula , una que no hace referencia a ningún objeto. nulo es el valor predeterminado de las variables de tipo de referencia.
Y '
ToString()
' es un método que puede ser llamado por una instancia de un objeto pero no por un literal.fuente
String.Empty
no es igual anull
. Simplemente se trata de la misma manera en algunos métodos comoString.Concat
. Por ejemplo, si tiene una variable de cadena establecida ennull
, C # no la reemplazaráString.Empty
si intenta llamar a un método.null
no es tratado comoString.Empty
por C #, solo es tratado asíString.Concat
, que es lo que llama el compilador de C # cuando agrega cadenas."abc" + null
se traduceString.Concat("abc", null)
e internamente ese método reemplazanull
conString.Empty
. La segunda parte es completamente correcta.En el marco COM que precedió a .net, era necesario que cualquier rutina que recibiera una cadena lo liberara cuando terminara. Debido a que era muy común que las cadenas vacías se pasaran dentro y fuera de las rutinas, y porque el intento de "liberar" un puntero nulo se definía como una operación legítima de no hacer nada, Microsoft decidió que un puntero de cadena nula representara una cadena vacía.
Para permitir cierta compatibilidad con COM, muchas rutinas en .net interpretarán un objeto nulo como una representación legal como una cadena vacía. Con un par de cambios leves .net y sus idiomas (lo que permite que los miembros de la instancia indiquen "no invocar como virtual"), Microsoft podría haber hecho que los
null
objetos de tipo declarado String se comporten aún más como cadenas vacías. Si Microsoft hubiera hecho eso, también habría tenido que hacer que elNullable<T>
trabajo fuera algo diferente (para permitir,Nullable<String>
algo que deberían haber hecho en mi humilde opinión de todos modos) y / o definir unNullableString
tipo que sería en su mayoría intercambiableString
, pero que no consideraría unnull
como una cadena vacía válida.Tal como están las cosas, hay algunos contextos en los que a
null
se considerará una cadena vacía legítima y otros en los que no. No es una situación terriblemente útil, pero una que los programadores deben tener en cuenta. En general, las expresiones del formulariostringValue.someMember
fallarán sistringValue
es asínull
, pero la mayoría de los métodos y operadores de marco que aceptan cadenas como parámetros se consideraránnull
como una cadena vacía.fuente
'+'
es un operador infijo. Como cualquier operador, realmente está llamando a un método. Podrías imaginar una versión no infija"wow".Plus(null) == "wow"
El implementador ha decidido algo como esto ...
Entonces ... tu ejemplo se convierte
que es lo mismo que
En ningún momento nulo se convierte en una cadena. Entonces
null.ToString()
no es diferente esonull.VoteMyAnswer()
. ;)fuente
var bob = Plus(Plus(Plus(Plus("abc",null),null),null),"123");
. Las sobrecargas de los operadores son métodos estáticos en su esencia: msdn.microsoft.com/en-us/library/s53ehcz3(v=VS.71).aspx Si no lo fueran,var bob = null + "abc";
o especialmentestring bob = null + null;
no serían válidos.Supongo que porque es un literal que no se refiere a ningún objeto.
ToString()
necesita unobject
.fuente
Alguien dijo en este hilo de discusión que no se puede hacer una cadena de la nada. (que es una bonita frase como creo). Pero sí, puedes :-), como muestra el siguiente ejemplo:
funciona bien y no arroja una excepción en absoluto. La única diferencia es que debe convertir uno de los valores nulos en una cadena: si elimina la conversión (cadena) , el ejemplo aún se compila, pero arroja una excepción en tiempo de ejecución: "Operador '+' es ambiguo en operandos de escriba '<nulo>' y '<nulo>' ".
Nota: en el ejemplo de código anterior, el valor de x no es nulo como podría esperarse, en realidad es una cadena vacía después de haber convertido uno de los operandos en una cadena.
Otro hecho interesante es que en C # / .NET la forma en que
null
se trata no siempre es la misma si se consideran diferentes tipos de datos. Por ejemplo:Con respecto a la primera línea del fragmento de código: si
x
es una variable entera anulable (es decir, queint?
contiene un valor)1
, está obteniendo el resultado<null>
. Si es una cadena (como se muestra en el comentario) con valor"1"
, entonces está"1"
regresando en lugar de hacerlo<null>
.Nota: también es interesante: si está utilizando
var x = 1;
la primera línea, obtendrá un error de tiempo de ejecución. ¿Por qué? Debido a que la asignación convertirá la variablex
en el tipo de datosint
, que no es anulable. El compilador no asumeint?
aquí, y por lo tanto falla en la segunda línea dondenull
se agrega.fuente
Agregar
null
a una cadena simplemente se ignora.null
(en su segundo ejemplo) no es una instancia de ningún objeto, por lo que ni siquiera tiene unToString()
método. Es solo un literal.fuente
Porque no hay diferencia entre
string.Empty
ynull
cuando concatene cadenas. Puede pasar nulostring.Format
también. Pero está intentando llamar a un métodonull
, que siempre daría como resultadoNullReferenceException
ay, por lo tanto, genera un error de compilación.Si por alguna razón realmente desea hacerlo, puede escribir un método de extensión, que verifica
null
y luego regresastring.Empty
. Pero una extensión como esa solo debería usarse cuando sea absolutamente necesario (en mi opinión).fuente
Como general: puede o no ser válido aceptar nulo como parámetro dependiendo de la especificación, pero siempre es inválido llamar a un método en nulo.
Ese es otro tema por el cual los operandos del operador + pueden ser nulos en el caso de cadenas. Esto es algo de VB (lo siento chicos) para facilitar la vida de los programadores, o suponiendo que el programador no pueda lidiar con los valores nulos. Estoy completamente en desacuerdo con esta especificación. 'desconocido' + 'cualquier cosa' debería seguir siendo 'desconocido' ...
fuente