2009-06-07 14 views
8

Cada vez que escribo alguna clase de datos, suelo pasar tanto tiempo escribiendo la implementación de IEquatable.Ayudantes de implementación de métodos iguales (C#)

La última clase que escribí fue algo así como:

public class Polygon 
{ 
    public Point[] Vertices { get; set; } 
} 

Ejecución IEquatable era exaustive. Seguramente C# 3.0/LINQ ayuda mucho, pero los vértices se pueden desplazar y/o en el orden inverso, y eso agrega mucha complejidad al método Equals. Después de muchas pruebas unitarias, y la implementación correspondiente, me di por vencido, y cambié mi aplicación para aceptar solo triángulos, cuya implementación de IEquatable requería solo 11 pruebas unitarias para estar completamente cubiertas.

¿Hay alguna herramienta o técnica que ayude a implementar Equals y GetHashCode?

+0

Usted parece no estar buscando Igual a la generación de código, pero para un implementador algoritmo genérico. Creo que no tienes suerte aquí. – erikkallen

Respuesta

8

Uso ReSharper para generar miembros con igualdad. Opcionalmente implementará IEquatable<T> y reemplazará a los operadores si así lo desea (lo que por supuesto nunca hace, pero de todos modos es genial).

La implementación de Equals incluye una anulación de Object.Equals(Object), así como una variante fuertemente tipada (que puede evitar la verificación innecesaria de tipos). La versión de menor tipeo llama a la fuertemente tipada después de realizar una verificación de tipo. La versión fuertemente tipada realiza una verificación de igualdad de referencia (Object.ReferenceEquals(Object,Object)) y luego compara los valores de todos los campos (bueno, solo aquellos que le indica al generador que incluyan).

En cuanto a GetHashCode, una factorización inteligente de GetHashCode los valores del campo se combinan (usando unchecked para evitar excepciones de desbordamiento si se utiliza la opción del compilador checked). Cada uno de los valores del campo (aparte del primero) se multiplica por números primos antes de combinarse. También puede especificar qué campos nunca serán nulos, y eliminará cualquier comprobación nula.

Esto es lo que se obtiene por su clase Polygon pulsando ALT+Insert luego seleccionando "Generar Igualdad miembros":

public class Polygon : IEquatable<Polygon> 
{ 
    public Point[] Vertices { get; set; } 

    public bool Equals(Polygon other) 
    { 
     if (ReferenceEquals(null, other)) return false; 
     if (ReferenceEquals(this, other)) return true; 
     return Equals(other.Vertices, Vertices); 
    } 

    public override bool Equals(object obj) 
    { 
     if (ReferenceEquals(null, obj)) return false; 
     if (ReferenceEquals(this, obj)) return true; 
     if (obj.GetType() != typeof (Polygon)) return false; 
     return Equals((Polygon) obj); 
    } 

    public override int GetHashCode() 
    { 
     return (Vertices != null ? Vertices.GetHashCode() : 0); 
    } 
} 

Algunas de las características que hablé anteriormente no se aplican ya que sólo hay un campo . Tenga en cuenta también que no ha verificado el contenido de la matriz.

En general, ReSharper extrae una gran cantidad de código excelente en cuestión de segundos. Y esa característica es bastante baja en mi lista de cosas que hace que ReSharper sea una herramienta increíble.

+0

¡No es mágico, pero seguramente ayuda! Gracias –

+2

Igual que la anulación (obj) no parece un código excelente para mí. ¿No sería más natural decir simplemente devolver esto. Clasificaciones (obj como Polígono)? – mquander

+0

Quizás un código más simple de leer, sí. Pero las características de rendimiento serían peores. El JIT reducirá la primera línea a una instrucción simple de código de máquina (cmp con cero) que será muy rápido de ejecutar.La segunda línea reduce a otra instrucción de código de máquina simple (punteros cmp obj) que también será muy rápido de ejecutar. La tercera línea realiza una comprobación de tipo (el JIT optimiza esto hasta otra verificación de puntero basada en el código de tipo del objeto), y solo finalmente, si las comprobaciones anteriores fallan, se llama igual a Igual. –

2

Para comparar dos matrices de elementos, utilizo el método de extensión SequenceEqual.

En cuanto a un igual genérico y GetHashCode, hay una técnica basada en la serialización que podría funcionar para usted.

Using MemoryStream and BinaryFormatter for reuseable GetHashCode and DeepCopy functions

+0

Gracias por agregarlo a mi conjunto de herramientas. –

+0

No pude encontrar SequenceEqual en 3.5/System.Core.dll, ¿sabes dónde está? Estoy usando el Reflector de Red Gate para ver el código fuente. –

+0

¡Buen artículo! Ahora me di cuenta de que escribir la implementación de Equals es tonto, todo lo que tienes que hacer es implementar GetHashCode y luego usarlo en Equals. –