c# nullable

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.

Me pregunto cuál es la diferencia entre las dos siguientes declaraciones:

  1. Causa una NullReferenceException - está bien.

    object test1 = default(int?); object result = test1.ToString();

  2. Devuelve una cadena vacía "", ¿por qué?

    object test2 = default(int?).ToString();

  3. 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?"). }

  4. 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> ).