El ejercicio de programación ilustra varias propiedades de la igualdad en C#:
Object.Equals()== y !=. Esto se considera más idiomático que usar el método Equals(), que también está disponible con estos tipos. Quienes programan en Java deben tener en cuenta, cuando trabajan con strings, que == compara por valor en C# pero por referencia en Java al volver a su lenguaje anterior.Equals() heredado de object. Si tu objetivo con la prueba de igualdad es asegurarte de que dos objetos son exactamente la misma instancia, basta con confiar en la implementación de object. Si no es así, necesitas sobrescribir object.Equals().Equals().Equals() sobrescrito contendrá pruebas de igualdad sobre miembros de tipos simples usando ==, y sobre tipos de referencia con llamadas recursivas a Equals().class StatusBar
{
private readonly int width = 200, height = 20;
public override bool Equals(object other)
{
// ... null and type checks and performance optimisations
return width == (other as StatusBar).width && height == (other as StatusBar).height;
}
}
class Window
{
private readonly string title = "Main";
private readonly StatusBar statusBar = new StatusBar();
public override bool Equals(object other)
{
// ... null and type checks and performance optimisations
return title == (other as Window).title && statusBar.Equals((other as Window).statusBar);
}
}
object.ReferenceEquals() se usa para comparar dos objetos y detectar si son una misma instancia. Esto aporta claridad y es una necesidad cuando se han sobrescrito o sobrecargado Equals() y ==.var winA = new Window(); // above code shows that all windows are equal
var winB = new Window();
ReferenceEquals(winA, winB);
// => false
var winC = winA;
ReferenceEquals(winA, winC);
// => true
public override bool Equals(object obj), los IDE normalmente generan la sobrecarga protected bool Equals(FacialFeatures other) para usarla cuando hay herencia. Una clase derivada puede llamar al Equals() de la clase base y luego agregar su propia prueba.== a menos que hayas sobrecargado el operador ==, además del método Equals() en tu clase (consulta el ejercicio operator-overloading), o a menos que solo te importe que las referencias sean iguales.structs se tratan en el ejercicio structs.tuples se trata en el ejercicio tuples.protected bool Equals(T other)
{
return field1 == other.field1 && field2.Equals(other.field2);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((T) obj);
}
SequenceEquals(), pero en ausencia de LINQ se trata de iterar por ambas colecciones y comparar los elementos uno por uno.== y != con tus propias clases, consulta el ejercicio operator-overloading.Object.GetHashCode()object.GetHashCode() devuelve un código hash en forma de entero de 32 bits. Las clases de diccionario y de conjunto, como Dictionary<T> y HashSet<T>, usan el código hash para almacenar y recuperar objetos de forma eficiente. En el caso de los diccionarios, el hashing se relaciona con las claves.Equals(), también sobrescribas GetHashCode(). Existe una relación entre Equals() y GetHashCode() que debe cumplirse para el comportamiento correcto de las clases de diccionario y de conjunto de hash, y de cualquier otra que use un código hash. Se espera que implementes el método de modo que no dejes trampas para quienes mantienen el código y que podrían agregar más adelante una colección basada en códigos hash.Equal() devuelve true), entonces GetHashCode() debe devolver el mismo valor para ambos objetos. Esto no se aplica en la dirección inversa. No es simétrico. Imagina una función de búsqueda que primero va a un «bucket» según el código hash y luego elige el elemento concreto usando la prueba de igualdad.HashCode.Combine() pasando los valores usados en la prueba de igualdad (o un subconjunto). Ten en cuenta que, cuanta más información proporciones a Combine(), más eficiente será probablemente la implementación del hash.public class Assessment
{
private int rating;
private Person boss;
public override int GetHashCode()
{
return HashCode.Combine(rating, boss);
}
}
Para mejorar un poco el rendimiento, sobre todo cuando los objetos pertenecen a colecciones, puedes agregar un miembro sobrecargado public bool Equals(T other).
Esto ahorrará cierta cantidad de comprobaciones de tipo para los tipos de referencia y ahorrará un paso de boxing para los tipos de valor, ya que no será necesario convertirlos a un objeto (boxing) como argumento de public override bool Equals(object other).
Si agregas la interfaz IEquatable<T> a tu clase, esto requerirá que se implemente la sobrecarga. A menos que tu código contenga rutinas que acepten objetos de tipo IEquatable<T> (y que, supuestamente, hagan algo interesante relacionado con la igualdad, sea cual sea la clase que lo implemente), en realidad no hay ninguna otra razón de peso para incluir la interfaz.
IEqualityComparer<T>Si tienes una clase que se puede identificar de forma única de dos maneras distintas, por ejemplo una clase Person que tiene un SSID y una dirección de correo electrónico única, .NET ofrece un mecanismo para que dos colecciones diferentes usen pruebas de igualdad y códigos hash distintos. Cada una puede tener una implementación diferente de IEqualityComparer<T> con su propio método Equals() y su propio GetHashCode(). Puedes tener un diccionario cuya clave sea el SSID y otro cuya clave sea la dirección de correo electrónico.
Cuando entra en juego IEqualityComparer<T>, normalmente seguirás sobrescribiendo Equals() y GetHashCode() en tu clase de elemento para evitar problemas fuera de las clases de colección.
Una consideración al usar IEqualityComparer<T> es que los métodos privados, etc., no estarán disponibles para la prueba de igualdad.
Si solo hay una colección con hash en juego, puede ser mejor evitar IEqualityComparer<T> y encapsular la igualdad y el código hash en el propio objeto. No es lo ideal, para empezar, que el compilador no pueda hacer cumplir una dependencia clave como la que existe entre el objeto y la colección con hash, pero si la lógica de hash y de comparación está en otro lugar, sería aún más fácil que quien mantiene el código haga cambios en los miembros de una clase sin tener en cuenta las consecuencias para la colección.
Un primitivo que puede poner a prueba a quien programa sin estar atento es comprobar la igualdad de valores de punto flotante. Esto se trata en el documento about.md del concepto floating-point-numbers.
Este artículo muestra algunas de las decisiones que hay que tomar con respecto a la igualdad y la herencia. Solo te concernirán si estás manipulando instancias de una clase y de una clase derivada, y necesitas comprobar la igualdad entre ambas.