valores valor utilice tipo ternario que puede porque operador convertir condicional acepte acepta c# casting null il

valor - operador condicional en c#



¿Por qué el compilador me permite convertir un valor nulo en un tipo específico en C#? (9)

Considera este código:

var str = (string)null;

Cuando escriba el código, este es mi código IL :

IL_0001: ldnull

E IL tiene cualquier operador de Cast pero:

var test = (string) new Object();

El código IL es:

IL_0008: castclass [mscorlib]System.String

Por lo tanto, se ignoró Casting null to string .

¿Por qué el compilador me permite convertir un null en un tipo específico?


Creo que deberías leer la especificación. Puedes lanzar un valor nulo a cada uno que desees. Míralo:

• Desde el literal nulo hasta cualquier tipo de referencia.

Justo antes de usar el valor que verifica para nulo.


El objetivo del elenco es definir str como un tipo de cadena, por lo tanto, se trata menos de si se puede convertir un nulo como un tipo y más acerca de cómo definir el tipo de la variable.


En IL en este nivel, null es simplemente null . El compilador sabía que era null porque eso es lo que escribiste, por lo que el compilador no necesita llamar al operador de transmisión. Lanzar null a un objeto simplemente producirá null .

Entonces, esta es una "optimización" o simplificación en tiempo de compilación si se quiere.

Como esto es legal, para emitir null a otro tipo de objeto, no hay una advertencia ni un error informado por esto.

Tenga en cuenta que, al parecer, el compilador no hará esto, aunque cree que puede verificar que el valor que se está emitiendo está garantizado que es null , si no es un literal.

Tu ejemplo:

void Main() { var s = (string)null; GC.KeepAlive(s); }

ILLINOIS:

IL_0000: ldnull IL_0001: stloc.0 // s IL_0002: ldloc.0 // s IL_0003: call System.GC.KeepAlive

( GC.KeepAlive la llamada a GC.KeepAlive para evitar que el compilador GC.KeepAlive toda la variable debido a que no se usa en ninguna parte).

Si meto el null en un objeto primero, sin posibilidad de que cambie:

void Main() { object o = null; var s = (string)o; GC.KeepAlive(s); }

ILLINOIS:

IL_0000: ldnull IL_0001: stloc.0 // o IL_0002: ldloc.0 // o IL_0003: castclass System.String IL_0008: stloc.1 // s IL_0009: ldloc.1 // s IL_000A: call System.GC.KeepAlive


En Java hay al menos un caso en el que necesita convertir un null a algún tipo, y es cuando usa métodos sobrecargados para decirle al compilador qué método desea ejecutar (supongo que este también es el caso en C #). Como un null es 0 (o lo que sea que el puntero sea null ), sin importar de qué tipo sea, no verá ninguna diferencia en el código compilado (aparte del método que se llamó).


La conversión de un valor nulo es perfectamente válida; a veces se requiere cuando se pasan argumentos a métodos sobrecargados para informar al compilador qué método se está invocando.

Vea la siguiente pregunta relacionada:

Casting null como un objeto?


No todo lo que parece una (SomeType)expression es realmente un elenco, en C #. A veces, la expresión necesita adquirir un tipo que no tenía ya. Algunos otros ejemplos:

var a = (short)42; var b = (Func<int, int>)(i => i + 1); var c = (IConvertible)"Hello";

En cada uno de estos casos, también se podría haber escrito el tipo de la izquierda, en lugar de var , si se prefiere. Pero este no es siempre el caso cuando la expresión es parte de una expresión más grande, por ejemplo:

CallOverloadedMethod((short)42); // CallOverloadedMethod has another overload that we don''t want var y = b ? x : (IConvertible)"Hello"; // the ?: operator might not be able to figure out the type without this hint

En su ejemplo, el null literal no tiene ningún tipo en sí mismo. En algunos casos, como cuando se elige entre muchas sobrecargas, como cuando se utiliza el operador ternary ?: O cuando se declara una variable con sintaxis var , es necesario tener una expresión que todavía sea null pero que también lleve un tipo.

Tenga en cuenta que las sobrecargas también incluyen operadores, por ejemplo en:

public static bool operator ==(Giraffe g1, Giraffe g2) { if (g1 == (object)null && g2 != (object)null || g1 != (object)null && g2 == (object)null) { return false; } // rest of operator body here ... }

la sintaxis (object)null se usa para garantizar que la sobrecarga definida por el usuario de == no se llame recursivamente.


Porque la especificación así lo dice. Ver §6.1.5, §6.2 y §7.7.6 del estándar C # 5 . Para citar solo las partes relevantes:

§7.7.6 Expresiones de molde

Una expresión de conversión de la forma (T)E , donde T es un tipo y E es una expresión unaria , realiza una conversión explícita (§6.2) del valor de E para escribir T [... T] el resultado es el valor producido por la conversión explícita.

§6.2 Conversiones explícitas

Las siguientes conversiones se clasifican como conversiones explícitas:

  • Todas las conversiones implícitas

§6.1.5 Conversiones de referencia implícitas

Las conversiones de referencia implícitas son:

  • Desde el literal nulo hasta cualquier tipo de referencia .

Su sintaxis es correcta y no hay limitaciones de especificación en c #. Estas son reglas de especificación:

Las conversiones de referencia implícitas son:

  • De cualquier tipo de referencia a objeto y dinámico.

  • De cualquier tipo de clase S a cualquier tipo de clase T, siempre que S se derive de T.

  • De cualquier tipo de clase S a cualquier tipo de interfaz T, siempre que S implemente T.

  • Desde cualquier tipo de interfaz S a cualquier tipo de interfaz T, siempre que S se derive de T.

  • Desde una matriz tipo S con un elemento tipo SE a una matriz tipo T con un elemento tipo TE, siempre que todos los siguientes sean verdaderos: o S y T difieren solo en el tipo de elemento. En otras palabras, S y T tienen el mismo número de dimensiones. o Tanto SE como TE son tipos de referencia. o Existe una conversión de referencia implícita de SE a TE.

  • Desde cualquier tipo de matriz a System.Array y las interfaces que implementa.

  • Desde una matriz unidimensional tipo S [] a System.Collections.Generic.IList y sus interfaces base, siempre que exista una identidad implícita o conversión de referencia de S a T.

  • Desde cualquier tipo de delegado hasta System.Delegate y las interfaces que implementa.

  • Desde el literal nulo hasta cualquier tipo de referencia.

  • De cualquier tipo de referencia a un tipo de referencia T si tiene una identidad implícita o conversión de referencia a un tipo de referencia T0 y T0 tiene una conversión de identidad a T.

  • Desde cualquier tipo de referencia a una interfaz o delegar tipo T si tiene una identidad implícita o conversión de referencia a una interfaz o tipo de delegado T0 y T0 es convertible en varianza (§13.1.3.2) a T.

  • Conversiones implícitas que implican parámetros de tipo que se sabe que son tipos de referencia. Ver §6.1.10 para más detalles sobre conversiones implícitas que involucran parámetros de tipo. Las conversiones de referencia implícitas son aquellas conversiones entre tipos de referencia que se puede probar que siempre tienen éxito, y por lo tanto no requieren controles en tiempo de ejecución. Las conversiones de referencia, implícitas o explícitas, nunca cambian la identidad referencial del objeto que se está convirtiendo. En otras palabras, aunque una conversión de referencia puede cambiar el tipo de referencia, nunca cambia el tipo o valor del objeto al que se hace referencia.


Supongamos que el compilador devuelve una advertencia para var str = (string)null; . Entonces, ¿esta línea debe var str = SomeFunctionThatReturnsNull() ?: var str = SomeFunctionThatReturnsNull() Al usar var, el compilador debe saber qué tipo se supone debe inicializar en tiempo de compilación, y tampoco importa si va a poner un valor nulo en él como siempre y cuando se declare como un tipo anulable. No es sorprendente ver que el compilador no está llamando Cast en caso nulo porque no hay nada que emitir.