ventajas tutorial sharp programacion lenguaje desventajas descargar caracteristicas c# cil il notnull binary-operators

tutorial - ¿Por qué el compilador de C#traduce esto!=Comparación como si fuera una> comparación?



lenguaje de programacion c# caracteristicas (1)

Respuesta corta:

No existe una instrucción "comparar-no-igual" en IL, por lo que el operador C # != tiene correspondencia exacta y no puede traducirse literalmente.

Sin embargo, existe una instrucción "comparar-igual" ( ceq , una correspondencia directa con el operador == ), por lo que en el caso general, x != y se traduce como su equivalente ligeramente más largo (x == y) == false .

También hay una instrucción "compare-mayor-que" en IL ( cgt ) que permite al compilador tomar ciertos atajos (es decir, generar un código IL más corto), uno de los cuales es la comparación de desigualdad de objetos contra nulo, obj != null , traducir como si fueran " obj > null ".

Vamos a entrar en más detalles.

Si no hay una instrucción "comparar-no-igual" en IL, entonces, ¿cómo el compilador traducirá el siguiente método?

static bool IsNotEqual(int x, int y) { return x != y; }

Como ya se dijo anteriormente, el compilador convertirá x != y en (x == y) == false :

.method private hidebysig static bool IsNotEqual(int32 x, int32 y) cil managed { ldarg.0 // x ldarg.1 // y ceq ldc.i4.0 // false ceq // (note: two comparisons in total) ret }

Resulta que el compilador no siempre produce este patrón bastante largo. Veamos qué sucede cuando reemplazamos y con la constante 0:

static bool IsNotZero(int x) { return x != 0; }

La IL producida es algo más corta que en el caso general:

.method private hidebysig static bool IsNotZero(int32 x) cil managed { ldarg.0 // x ldc.i4.0 // 0 cgt.un // (note: just one comparison) ret }

El compilador puede aprovechar el hecho de que los enteros con signo se almacenan en el complemento de dos (donde, si los patrones de bits resultantes se interpretan como enteros sin signo, eso es lo que significa .un , 0 tiene el valor más pequeño posible), por lo que traduce x == 0 como si no estuviera unchecked((uint)x) > 0 .

Resulta que el compilador puede hacer lo mismo para las comprobaciones de desigualdad contra null :

static bool IsNotNull(object obj) { return obj != null; }

El compilador produce casi el mismo IL que para IsNotZero :

.method private hidebysig static bool IsNotNull(object obj) cil managed { ldarg.0 ldnull // (note: this is the only difference) cgt.un ret }

Aparentemente, el compilador puede asumir que el patrón de bits de la referencia null es el patrón de bits más pequeño posible para cualquier referencia de objeto.

Este acceso directo se menciona explícitamente en el Estándar Anotado de Infraestructura de Lenguaje Común (primera edición de octubre de 2003) (en la página 491, como una nota al pie de la Tabla 6-4, "Comparaciones binarias u operaciones de sucursal"):

" cgt.un está permitido y es verificable en ObjectRefs (O). Esto se usa comúnmente cuando se compara un ObjectRef con un valor nulo (no existe una instrucción" comparar-no-igual ", que de lo contrario sería una solución más obvia)".

Por pura casualidad descubrí que el compilador de C # activa este método:

static bool IsNotNull(object obj) { return obj != null; }

... en este CIL :

.method private hidebysig static bool IsNotNull(object obj) cil managed { ldarg.0 // obj ldnull cgt.un ret }

... o, si prefiere mirar el código C # descompilado:

static bool IsNotNull(object obj) { return obj > null; // (note: this is not a valid C# expression) }

¿Cómo es que el != traduce como " > "?