c# - ¿Por qué la declaración nula ToString() devuelve una cadena vacía?
tostring java (2)
En C, uno usa el token .
para acceder a un miembro del operando izquierdo, y ->
para acceder a un miembro de la cosa a la que el operando izquierdo sostiene un puntero (referencia). Se produce una referencia nula si el operando de la izquierda de ->
es nulo. En C #, el .
tiene el primer significado cuando se aplica a los tipos de valor y el último significado cuando se aplica a los tipos de clase; utilizando .
en C # en una variable de tipo de clase que es nula desencadenará una NullReferenceException
.
El tipo .NET Nullable<T>
es una estructura de dos campos que contiene un campo booleano que indica si tiene un valor significativo (no nulo) y un campo de valor tipo T
para indicar cuál es ese valor (si no es nulo). Aunque el compilador permitirá que se asigne un Nullable<T>
a Nullable<T>
o que se compare uno con nulo, el null
en el primer caso es realmente una abreviatura para una instancia predeterminada (donde el indicador "has-value" es falso, y el valor el campo contiene el valor predeterminado para el tipo T), y la comparación con nulo es realmente una abreviatura para verificar la propiedad HasValue
(que a su vez se ve en el campo Boolean
). Invocar ToString
en, por ejemplo, una Nullable<int>
que es "nula" no es diferente semánticamente de invocarla en cualquier otra estructura que contenga un Boolean
y un Int32
que tengan los valores False
y 0
, respectivamente. Hay algunas formas en las que los compiladores tratan los tipos que Nullable<int>
valores NULL "especialmente", pero un valor Nullable<int>
predeterminado contiene [False, 0]
, no una referencia nula.
Tenga en cuenta que el primer ejemplo se lanza debido a una de las reglas "especiales" que el marco aplica a los tipos anulables. La conversión de un tipo de valor en Object
u otro tipo de referencia generalmente indica al tiempo de ejecución que cree un objeto que se comporte como un objeto de clase con campos y miembros que coincidan con los de la estructura y que devuelva una referencia a ese nuevo objeto, un proceso conocido como "boxeo ". Debido a que los diseñadores de tipos anulables querían permitir que el código dijera if (NullableThing == null)
lugar de (IMHO sematicamente más claro) if (!NullableThing.HasValue)
, el tiempo de ejecución se implementó de manera que el HasValue
un HasValue
cuyo campo HasValue
es falso produce una referencia nula en lugar de una referencia a una instancia de Nullable<T>
con valor predeterminado. Si bien creo que hay casos en los que tendría sentido que algunos tipos de valores usen diferentes métodos de caja y unbox, los tipos que admiten nulos son los únicos que pueden usar algo más que el boxeo normal.
Esta pregunta ya tiene una respuesta aquí:
Me pregunto cuál es la diferencia entre las dos siguientes declaraciones:
Causa una NullReferenceException - está bien.
object test1 = default(int?); object result = test1.ToString();
Devuelve una cadena vacía "", ¿por qué?
object test2 = default(int?).ToString();
Esto es lo mismo que 2.
int? test3 = null; if (test3.ToString() == string.Empty) //returns true { Console.WriteLine("int? = String.Empty, isn''t it strange?"). }
Y solo por diversión, puedo probar que bool puede ser igual al valor int (hmmm, ¿cómo? Bool puede ser solo falso, o verdadero y int nunca puede ser eso).
if (default(int?).ToString() == default(bool?).ToString()) //returns true because both are empty strings { Console.WriteLine("int = bool"); }
Nota: por defecto (int?) Devuelve null.
Un int?
es un Nullable<int>
. Nullable
es una estructura , que lo convierte en un tipo de valor, no en un tipo de referencia. test3
no está realmente configurado en null
. Asignarle un null
en realidad da como resultado la creación de una nueva estructura que simplemente tiene el campo HasValue
de esa estructura establecido en false
lugar de true
. (Se requiere un soporte especial del compilador para que se lleve a cabo una conversión implícita de este tipo; por lo tanto, no podría tener su propio tipo MyNullable<T>
que hizo esto).
Como el objeto que puede ToString
tiene un valor real, puede llamar a ToString
y proporcionar un valor significativo, en este caso, una cadena vacía.
Cuando encaja ese valor anulable colocándolo en una variable de object
, resultará en que se almacene un valor null
real en esa variable, razón por la cual obtiene un NRE cuando llama a un método.
Cuando un tipo de valor anulable está recuadrado, no encuadra el tipo de valor anulable; en cambio, si no tiene ningún valor, asigna un valor null
al objeto, si tiene un valor, ese valor subyacente se desenvuelve y luego se recorta. (Se requiere soporte especial del tiempo de ejecución para este comportamiento, que es otra razón por la que no puede crear su propio MyNullable<T>
).