c# - ¿Qué debe sobrescribirse en una estructura para garantizar que la igualdad funcione correctamente?
.net operators (6)
Desafortunadamente, no tengo la reputación suficiente para comentar otras entradas. Así que estoy publicando posibles mejoras a la mejor solución aquí.
Corrígeme, si estoy equivocado, pero la implementación mencionada anteriormente
public struct Complex
{
double re, im;
public override bool Equals(Object obj)
{
return obj is Complex && this == (Complex)obj;
}
public override int GetHashCode()
{
return re.GetHashCode() ^ im.GetHashCode();
}
public static bool operator ==(Complex x, Complex y)
{
return x.re == y.re && x.im == y.im;
}
public static bool operator !=(Complex x, Complex y)
{
return !(x == y);
}
}
Tiene un defecto importante. Me estoy refiriendo a
public override int GetHashCode()
{
return re.GetHashCode() ^ im.GetHashCode();
}
XORing es simétrico, por lo que Complex (2,1) y Complex (1,2) darían el mismo hashCode.
Probablemente deberíamos hacer algo más como:
public override int GetHashCode()
{
return re.GetHashCode() * 17 ^ im.GetHashCode();
}
Como dice el título: ¿necesito anular el operador ==
? ¿qué tal el método .Equals()
? ¿Algo que me falta?
La diferencia básica entre los dos es que el operador ==
es estático, es decir, el método apropiado para invocar se determina en tiempo de compilación, mientras que el método Equals
se invoca dinamicamente en una instancia.
Definir ambos es probablemente lo mejor que se puede hacer, incluso si esto importa menos en el caso de las estructuras, ya que las estructuras no se pueden extender (una estructura no puede heredar de otra).
La mayoría de las veces puede evitar la implementación de Estructuras y GetHashcode en las estructuras, porque hay una implementación automática por parte del compilador de los tipos de valor que utilizan contenido bit a bit + reflexión para los miembros de referencia.
Echa un vistazo a esa publicación: ¿cuál es mejor para el almacén de datos Struct / Classes?
Por lo tanto, para facilitar su uso, aún podría implementar == y! =.
Pero la mayoría de las veces puede evitar implementar Equals y GetHashcode.
Un caso donde tendrías que implementar Equals y GetHashCode es para un campo que no quieres tener en cuenta.
Por ejemplo, un campo que varía a medida que pasa el tiempo, como Age of a Person o instantSpeed de un automóvil (la identidad del objeto no debería cambiar si desea volver a encontrarla en el diccionario en el mismo lugar)
Saludos, mejor código
Solo por completitud también aconsejaría sobrecargar el método Equals
:
public bool Equals(Complex other)
{
return other.re == re && other.im == im;
}
esta es una mejora real del esfuerzo ya que no se produce el boxeo del argumento de entrada del método Equals(Object obj)
Algunas mejores prácticas para usar tipos de valores:
- hazlos inmutables
- anular Igual (el que toma un objeto como argumento);
- sobrecarga Es igual a tomar otra instancia del mismo tipo de valor (p. ej. * Igual (Compleja));
- operadores de sobrecarga == y! =;
- anular GetHashCode
Esto proviene de esta publicación: http://theburningmonk.com/2015/07/beware-of-implicit-boxing-of-value-types/
También debe implementar IEquatable <T>. Aquí hay un extracto de las Pautas de diseño del marco:
Implemente IEquatable en tipos de valores. El método Object.Equals en los tipos de valor causa el boxeo, y su implementación predeterminada no es muy eficiente porque utiliza la reflexión. IEquatable.Equals puede ofrecer un rendimiento mucho mejor y puede implementarse para que no cause el boxeo.
public struct Int32 : IEquatable<Int32> {
public bool Equals(Int32 other){ ... }
}
SÍ siga las mismas pautas que para anular Object.Equals cuando implemente IEquatable.Equals. Consulte la sección 8.7.1 para obtener instrucciones detalladas sobre la anulación de Object.Equals
Un ejemplo de msdn
public struct Complex
{
double re, im;
public override bool Equals(Object obj)
{
return obj is Complex && this == (Complex)obj;
}
public override int GetHashCode()
{
return re.GetHashCode() ^ im.GetHashCode();
}
public static bool operator ==(Complex x, Complex y)
{
return x.re == y.re && x.im == y.im;
}
public static bool operator !=(Complex x, Complex y)
{
return !(x == y);
}
}