2009-09-27 10 views
14

Estoy viendo un comportamiento diferente entre usar .Equals y == entre dos de las nuevas instancias Tuple <> .NET 4.0. Si he reemplazado Equals en el objeto en el Tuple <> y llamo .Equals en las Tuplas, se invocará la anulación de Equals. Si utilizo == en las Tuplas, no se llama a la anulación de Equals. ¿Es eso por diseño y tiene sentido?¿Se espera que este sea el comportamiento de igualdad de tuplas de C# 4.0?

EDIT: De las respuestas y los comentarios puedo decir que no estoy siendo claro. Sé que Tuple <> es un tipo de referencia y que para los tipos de referencia == comprobará la identidad (ReferenceEquals). Pero, ¿debería Tuple <> anular == para verificar la igualdad de los objetos que contiene? Por consistencia, probablemente no.

Por ejemplo si tengo un objeto simple

public class NameAndNumber 
{ 
    public int Number { get; set; } 
    public string Name { get; set; } 

    public override bool Equals(object obj) 
    { 
     if (obj is NameAndNumber) 
     { 
      NameAndNumber other = (NameAndNumber)obj; 
      return Number == other.Number && Name == other.Name; 
     } 

     return false; 
    } 
} 

y luego hago algo como esto:

Tuple<NameAndNumber, NameAndNumber> left = new Tuple<NameAndNumber, NameAndNumber>(
     new NameAndNumber { Name = "one", Number = 1 }, 
     new NameAndNumber { Name = "two", Number = 2 }); 
Tuple<NameAndNumber, NameAndNumber> right = new Tuple<NameAndNumber, NameAndNumber>(
     new NameAndNumber { Name = "one", Number = 1 }, 
     new NameAndNumber { Name = "two", Number = 2 }); 
bool operatorResult = left == right; 
bool equalsResult = left.Equals(right); 
Console.Out.WriteLine("operatorResult = {0} equalsResult = {1}", 
     operatorResult, equalsResult); 

consigo operatorResult = false equalsResult = true

¿Debo estar esperando ¿ese?

Sé que la implementación de Equals en NameAndNumber no es "correcta", simplemente se trata de un código de ejemplo simplificado.

También he intentado implementar IEquatable, ==,! = Y GetHashCode. Mismos resultados

+0

Gracias por las respuestas y comentarios. Debería haber esperado este comportamiento. Estoy reemplazando nuestros proyectos 3.5 Implementación de Tuple que escribimos nosotros mismos con la implementación de .NET 4. Nuestra Tupla se anuló == para obtener el comportamiento que esperaba en la pregunta. Así que me sorprendió cuando no se comportó exactamente como nuestro personalizado. –

Respuesta

13

Los resultados que se ven provenir de una design compromise, tuplas son ahora compartido entre F # y C#. El punto principal es que todas las Tuplas están de hecho implementadas como tipos de referencia, eso no fue tan obvio.

La decisión de si Tuples debería hacer verificaciones de igualdad profundas o superficiales se movió a dos interfaces: IStructuralComparable, IStructuralEquatable. Tenga en cuenta que esos 2 ahora también están implementados por la clase Array.

6

Para Tipo de referencia: == realiza una comparación de identidad, es decir, solo devolverá verdadero si ambas referencias apuntan al mismo objeto. Aunque se espera que el método Equals() realice una comparación de valores, es decir, devolverá verdadero si las referencias apuntan a objetos que son equivalentes.

Para los tipos de referencia, donde == tiene NO sido sobrecargado, se compara si dos referencias se refieren al mismo objeto

+3

A excepción de la cadena que es mágica. Así que supongo que estoy buscando más magia. ¿Esperaría una Tupla de tipos de valores para hacer una verificación de valor? No es así –

+5

No hay magia, simplemente ha sobrecargado == /! = Operadores; Puedes ver esto en el reflector como op_Equality y op_Inequality (en System.String). Sin embargo, ** es ** mágico en cosas como 'int' /' float' (definido en la especificación) y 'Nullable ' (que usa operadores "levantados"). –

+0

No estoy seguro de que entiendo completamente sus comentarios, su Tuple en su código de ejemplo es un tipo de referencia, ¿verdad? –

1

Por defecto, el operador == pruebas de referencia por la igualdad, por lo el resultado que están viendo se espera.

Ver Guidelines for Overriding Equals() and Operator == (C# Programming Guide):

En C#, hay dos tipos diferentes de la igualdad: la igualdad de referencia (también conocido como identidad) y la igualdad de valor. La igualdad de valor es generalmente el significado entendido de igualdad de : significa que dos objetos contienen los mismos valores . Por ejemplo, dos enteros con el valor de 2 tienen el valor igualdad. La igualdad de referencia significa que no hay dos objetos para comparar.

1

Por defecto, == (en una clase) significa igualdad de referencia; es decir, son la misma instancia; lo que object.ReferenceEquals(x,y) devolvería.

Puede proporcionar la suya == /!= Operadores para obtener el comportamiento esperado - y cuando se reemplaza Equals es importante para anular GetHashCode también (de lo contrario se rompe uso como clave - Why is it important to override GetHashCode when Equals method is overriden in C#?):

public static bool operator == (NameAndNumber x, NameAndNumber y) { 
    if (x == null && y == null) return true; 
    if (x == null || y == null) return false; 
    return x.Number == y.Number && x.Name == y.Name; 
    // or if polymorphism is important: return x.Equals(y); 
} 
public static bool operator !=(NameAndNumber x, NameAndNumber y) { 
    return !(x == y); // lazy but works 
} 
public override int GetHashCode() { 
    return (Name == null ? 0 : Name.GetHashCode()) + 
     17 * Number.GetHashCode(); 
} 
+1

Lo sé. Como mencioné, mostré una implementación simplificada y dejé GetHashCode para un ejemplo más pequeño. Pero eso no cambiará la forma en que funciona Tuple y no puedo agregar esos a Tuple. Puedo derivar de Tuple y agregarlos. –

+1

Si el problema es el polimorfismo, entonces haz que == use '.Equals', aparte de eso ... así es como funciona' == '. Si no lo sobrecarga, ¡no funcionará de esta manera! –

+0

@Marc Gravell. Supongo que el corazón de la pregunta está en si la clase Tuple incorporada en .net 4.0 se comporta de esta manera o no. ¿Debería actuar como un tipo de referencia estándar o delegar la verificación de igualdad a los objetos que contiene? Es solo un contenedor así que deberíamos importarnos si los dos contenedores son iguales o debería == verificar el contenido de los contenedores. Esta no es mi implementación de Tuple, está construida en .net 4 one. Las bibliotecas de terceros anteriores con una implementación Tuple o Pair anularían == verifican la igualdad de los objetos contenidos. –

Cuestiones relacionadas