Por comparación de igualdad de un tipo "T", la sobrecarga de estos métodos:
int GetHashCode() //Overrides Object.GetHashCode
bool Equals(object other) //Overrides Object.Equals; would correspond to IEquatable, if such an interface existed
bool Equals(T other) //Implements IEquatable<T>; do this for each T you want to compare to
static bool operator ==(T x, T y)
static bool operator !=(T x, T y)
Su código de comparación de tipo específico se debe hacer en un solo lugar: el métodoIEquatable<T>
interfaz de tipo seguro Equals(T other)
. Si está comparando con otro tipo (T2), implemente también IEquatable<T2>
y coloque el código de comparación de campo para ese tipo en Igual (T2 otro).
Todos los métodos y operadores sobrecargados deben enviar la tarea comparación de igualdad a las principales Iguales tipo-safe (t otro) método de instancia, de manera que una jerarquía de dependencia limpia se mantiene y garantías estrictas se introducen a cada nivel para eliminar la redundancia y no esencial complejidad.
bool Equals(object other)
{
if (other is T) //replicate this for each IEquatable<T2>, IEquatable<T3>, etc. you may implement
return Equals((T)other)); //forward to IEquatable<T> implementation
return false; //other is null or cannot be compared to this instance; therefore it is not equal
}
bool Equals(T other)
{
if ((object)other == null) //cast to object for reference equality comparison, or use object.ReferenceEquals
return false;
//if ((object)other == this) //possible performance boost, ONLY if object instance is frequently compared to itself! otherwise it's just an extra useless check
//return true;
return field1.Equals(other.field1) &&
field2.Equals(other.field2); //compare type fields to determine equality
}
public static bool operator ==(T x, T y)
{
if ((object)x != null) //cast to object for reference equality comparison, or use object.ReferenceEquals
return x.Equals(y); //forward to type-safe Equals on non-null instance x
if ((object)y != null)
return false; //x was null, y is not null
return true; //both null
}
public static bool operator !=(T x, T y)
{
if ((object)x != null)
return !x.Equals(y); //forward to type-safe Equals on non-null instance x
if ((object)y != null)
return true; //x was null, y is not null
return false; //both null
}
Discusión:
La implementación anterior centraliza el tipo específico (es decir, la igualdad de campo) comparación con el final de la ejecución IEquatable<T>
para el tipo. Los operadores ==
y !=
tienen una implementación paralela pero opuesta. Prefiero esto más que tener una referencia la otra, de modo que hay una llamada de método adicional para la dependiente. Si el operador !=
simplemente va a llamar al operador ==
, en lugar de ofrecer un operador con el mismo rendimiento, entonces también puede usar !(obj1 == obj2)
y evitar la llamada al método adicional. La comparación entre sí queda excluida del operador igual y de las implementaciones IEquatable<T>
, porque puede presentar 1. una sobrecarga innecesaria en algunos casos, y/o 2. un rendimiento incoherente según la frecuencia con la que una instancia se compara a sí misma frente a otra instancias.
Una alternativa que no me gusta, pero debería mencionar, es invertir esta configuración, centralizando en su lugar el código de igualdad específico del tipo en el operador de igualdad y los métodos Equals dependen de eso. Uno podría usar el atajo de ReferenceEquals(obj1,obj2)
para verificar la igualdad de referencia y la igualdad nula simultáneamente como lo mencionó Philip en una publicación anterior, pero esa idea es engañosa. Parece que estás matando a dos pájaros de un tiro, pero en realidad estás creando más trabajo: después de determinar que los objetos no son nulos ni tienen la misma instancia, entonces, además, tienes que verificar si cada instancia es nulo. En mi implementación, compruebas que una sola instancia sea nula exactamente una vez. En el momento en que se llama al método de instancia Equals, ya se ha descartado que el primer objeto que se compara sea nulo, por lo que todo lo que queda por hacer es comprobar si el otro es nulo. Entonces, después de como máximo dos comparaciones, saltamos directamente a la verificación de campo, sin importar qué método usemos (Equals(object),Equals(T),==,!=
). Además, como mencioné, si realmente está comparando y objetando a sí mismo la mayoría de las veces, entonces podría agregar esa verificación en el método Equals justo antes de sumergirse en las comparaciones de campo. El último punto para agregarlo es que aún puede mantener la jerarquía de flujo/dependencia sin introducir una verificación redundante/inútil en cada nivel.
¡Me acabo de dar cuenta de que tengo == y! = Sobrecargado! –
Creo que alguien cometió un error en la parte! = ¡Lo verifico! Thx por la pista. –
Correcto, las sobrecargas son incorrectas: si copia el código o la explicación de mi publicación a continuación, eliminaré mi publicación –