visual mayusculas importar comparestring comparar cadenas c# string reference pre-compilation

c# - mayusculas - ¿Por qué estas dos comparaciones de cadenas arrojan resultados diferentes?



string.compare c# (2)

Aquí hay un pequeño fragmento de código:

String a = "abc"; Console.WriteLine(((object)a) == ("ab" + "c")); // true Console.WriteLine(((object)a) == ("ab" + ''c'')); // false

Por qué ?


Porque el == está haciendo una comparación de referencia. Con el compilador de C # todas las cadenas "iguales" que se conocen en tiempo de compilación se "agrupan" juntas, de modo que

string a = "abc"; string b = "abc";

apuntará a la misma cadena "abc". Entonces serán referencialmente iguales.

Ahora, ("ab" + "c") se simplifica en el tiempo de compilación a "abc" , mientras que "ab" + ''c'' no, y por lo tanto no es referencialmente igual (la operación de concatenación se realiza en tiempo de ejecución).

Vea el código descompilado here

Añadiré que el Try Roslyn está haciendo una descompilación incorrecta :-) E incluso IlSpy :-(

Está descompilando a:

string expr_05 = "abc" Console.WriteLine(expr_05 == "abc"); Console.WriteLine(expr_05 == "ab" + ''c'');

Entonces, comparación de cuerdas. Pero al menos se puede ver claramente el hecho de que algunas cadenas se calculan en tiempo de compilación.

¿Por qué su código está haciendo una comparación de referencia? Debido a que está lanzando uno de los dos miembros para object , y el operator== en .NET no es virtual , por lo que debe resolverse en tiempo de compilación con la información que tiene el compilador, y luego ... desde == Operador

Para los tipos de valores predefinidos, el operador de igualdad (==) devuelve verdadero si los valores de sus operandos son iguales, de lo contrario es falso. Para tipos de referencia que no sean cadenas, == devuelve verdadero si sus dos operandos se refieren al mismo objeto. Para el tipo de cadena, == compara los valores de las cadenas.

Para el compilador, el primer operando del operador == no es una string (porque lo fundió), por lo que no cae en la comparación de string .

Dato interesante: en el nivel CIL (el lenguaje ensamblador de .NET), el opcode utilizado es el ceq , que hace una comparación de valores para los tipos de valores primitivos y una comparación de referencia para los tipos de referencia (por lo que al final siempre hace bit a bit comparación, con algunas excepciones para los tipos de flotación con NaN). No usa el operator== "especial" operator== métodos. Se puede ver en este example

donde el

Console.WriteLine(a == ("ab" + ''c'')); // True

se resuelve en tiempo de compilación en una llamada a

call bool [mscorlib]System.String::op_Equality(string, string)

mientras que los otros == son simplemente

ceq

Esto explica por qué el descompilador de Roslyn funciona "mal" (como el IlSpy :-(, ver informe de errores ) ... Ve un código de operación ceq y no verifica si hay un molde necesario para reconstruir la comparación correcta.

Holger preguntó por qué el compilador solo hace la suma entre dos literales de cadena ... Ahora, leyendo las especificaciones de C # 5.0 de una manera muy estricta, y considerando las especificaciones de C # 5.0 como "separadas" de las especificaciones de .NET (con el excepciones de los requisitos previos que el C # 5.0 tiene para algunas clases / structs / methods / properties / ...), tenemos:

Concatenación de cadenas:

string operator +(string x, string y); string operator +(string x, object y); string operator +(object x, string y);

Estas sobrecargas del operador binario + realizan una concatenación de cadenas. Si un operando de concatenación de cadenas es nulo, se sustituye una cadena vacía. De lo contrario, cualquier argumento que no sea cadena se convierte a su representación de cadena invocando el método virtual ToString heredado de tipo objeto. Si ToString devuelve null, se sustituye una cadena vacía.

Entonces, el caso string + string , string + null , null + string se describe con precisión, y su resultado se puede "calcular" usando solo las reglas de las especificaciones de C #. Para cualquier otro tipo, se debe virtual ToString método virtual ToString . El resultado del método virtual ToString no está definido para ningún tipo en las especificaciones de C #, por lo que si el compilador "presumió" su resultado, haría una "cosa" incorrecta. Por ejemplo, una versión de .NET que tuviera System.Boolean.ToString() que devolviera Yes / No lugar de True / False aún estaría bien para las especificaciones de C #.


dirección no igual. si quiere comparar un carácter de cadena, sugiera usar iguales.