2010-09-16 10 views
5

Me golpeó una extraña "asimetría" en C# que realmente no entiendo. Consulte el siguiente código:Object.Equals es virtual, pero Object.operator == no lo usa en C#?

using System; 
using System.Diagnostics; 
namespace EqualsExperiment 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      object apple = "apple"; 
      object orange = string.Format("{0}{1}", "ap", "ple"); 
      Console.WriteLine("1"); 
      Debug.Assert(apple.Equals(orange)); 
      Console.WriteLine("2"); 
      Debug.Assert(apple == orange); 
      Console.WriteLine("3"); 
     } 
    } 
} 

Puede ser obvio para todos los gurús de .NET, pero la segunda afirmación falla.

En Java, he aprendido que == es un sinónimo de algo llamado Object.ReferenceEquals aquí. En C#, pensé que Object.operator == usa Object.Equals, que es virtual, por lo que se reemplaza en la clase System.String.

¿Alguien puede explicar por qué la segunda afirmación falla en C#? ¿Cuáles de mis suposiciones son malas?

+0

Encontré una [respuesta] (http://stackoverflow.com/questions/1766492/c-overloading-operator-versus-equals/1849288#1849288) a mi pregunta también en otro hilo. Parece que 'object.operator ==' usa 'object.ReferenceEquals', pero' string.operator == 'usa' object.Equals'. Esto es contrario a la intuición para mí, porque 'object.Equals' es virtual, por lo que podría usarse ya en' object.operator == '. – wigy

Respuesta

7

El operador == no es un sinónimo, es un operador que se define para diferentes tipos.

El operador == se define para cuerdas, y luego se usa realmente el Equals método:

public static bool operator ==(string a, string b) { 
    return Equals(a, b); 
} 

Sin embargo, en su código que no está utilizando el operador de cadenas, que está utilizando en los objetos, entonces lo que obtienes es el operador == definido para objetos, que usa ReferenceEquals para hacer la comparación.

Qué sobrecarga del operador usar se decide en tiempo de compilación, por lo que es el tipo de variables que decide la sobrecarga, no el tipo real de los objetos a los que apuntan las variables.

+0

Hmmm. Entonces usted dice que Object.operator == se define con ReferenceEquals, mientras que String.operator == se define con Equals. ¿No es eso agradable e intuitivo? – wigy

+1

@wigy: la mayoría de las veces funciona muy bien, pero por supuesto hay situaciones como las de su ejemplo donde puede esperar que la comparación se determine en tiempo de ejecución. Sin duda es más intuitivo que, por ejemplo, en C++ y Java, donde no se puede usar el operador == en cadenas de manera confiable. En VB, el operador = determina la comparación en tiempo de ejecución, que está más en línea con la forma en que funciona VB, pero eso le da varias otras situaciones en las que puede sorprenderlo. En C# es posible determinar exactamente qué comparación se usará en el código, lo cual está más en línea con la forma en que C# funciona en general. – Guffa

+0

Gracias Guffa. Sé que es mejor que C, Java o VB. Los operadores de C++ pueden ser virtuales, por lo que tienes diferentes problemas allí.Es por eso que la mayoría de los estándares de codificación de C++ usan condiciones de Yoda como 'if (5 == algo) {...}' Entenderé que los diseñadores del framework pensaron que ReferenceEquals es más intuitivo para algunos de los codificadores, pero fijó la cadena .operator == por otro lado. – wigy

6

Los operadores se definen como métodos estáticos, por lo que no pueden participar en el polimorfismo. Por lo tanto, su segunda afirmación usa la definición de == para object (ya que sus variables se declaran como object), que solo prueba la igualdad de referencia. Si las variables se declararon como string, se habría utilizado la sobrecarga == para string, y la segunda afirmación habría tenido éxito.

+2

También vale la pena señalar, para completar, que el 'object.Equals estático (apple, orange)' devolvería 'true' en este caso. 'object.Equals' primero usa' == 'para verificar la igualdad de ref, y si eso falla utilizará' apple.Equals (orange) 'sobrecargado (suponiendo que' apple' y 'orange' no son' null') – LukeH

+0

Entiendo que uso 'bool estático Object.operator == (Object, Object)'. Pero todavía no entiendo, ¿por qué eso no llama 'Object.Equals (Object)'. Como eso es virtual, al final se llamaría a 'String.Equals (Object)' correcto. – wigy

Cuestiones relacionadas