¿Cuál es la diferencia entre IEquatable y simplemente anulando Object.Equals ()?

Quiero que mi clase de Food pueda probar cuando sea igual a otra instancia de Food . Más tarde lo List.Contains() contra una Lista, y quiero usar su método List.Contains() . ¿Debería implementar IEquatable o simplemente anular Object.Equals() ? Desde MSDN:

Este método determina la igualdad mediante el uso del comparador de igualdad predeterminado, tal como se define en la implementación del método IEquatable.Equals para T (el tipo de valores en la lista).

Entonces mi siguiente pregunta es: ¿qué funciones / clases del framework .NET usan Object.Equals() ? ¿Debería usarlo en primer lugar?

La razón principal es el rendimiento. Cuando se introdujeron los generics en .NET 2.0, pudieron agregar un montón de clases ordenadas como List , Dictionary , HashSet , etc. Estas estructuras hacen un uso intensivo de GetHashCode e Equals . Pero para los tipos de valores, esto requiere boxeo. IEquatable permite que una estructura implemente un método Equals fuertemente tipado, por lo que no se requiere boxeo. Por lo tanto, un rendimiento mucho mejor cuando se usan tipos de valores con colecciones genéricas.

Los tipos de referencia no se benefician tanto, pero la IEquatable le permite evitar un lanzamiento de System.Object que puede marcar la diferencia si se llama con frecuencia.

Como se señaló en el blog de Jared Parson , aún debe implementar las anulaciones de objeto.

De acuerdo con MSDN :

Si implementa IEquatable(T) , también debe anular las implementaciones de clase base de Object.Equals(Object) y GetHashCode para que su comportamiento sea coherente con el del IEquatable(T).Equals . Si anula Object.Equals(Object) , su implementación anulada también se llama en llamadas al método estático Equals(System.Object, System.Object) en su clase. Esto garantiza que todas las invocaciones del método Equals devuelvan resultados consistentes.

Por lo tanto, parece que no existe una diferencia funcional real entre los dos, excepto que se podría llamar a cualquiera de los dos, dependiendo de cómo se use la clase. Desde el punto de vista del rendimiento, es mejor utilizar la versión genérica porque no hay una penalización de box / unboxing asociada.

Desde un punto de vista lógico, también es mejor implementar la interfaz. Anular el objeto realmente no le dice a nadie que su clase es realmente equitativa. La anulación puede ser simplemente una clase de “no hacer nada” o una implementación superficial. El uso de la interfaz dice explícitamente: “¡Oye, esto es válido para la verificación de igualdad!” Es solo un mejor diseño.

Extendiendo lo que Josh dijo con un ejemplo práctico. +1 a Josh – Estaba a punto de escribir lo mismo en mi respuesta.

 public abstract class EntityBase : IEquatable { public EntityBase() { } #region IEquatable Members public bool Equals(EntityBase other) { //Generic implementation of equality using reflection on derived class instance. return true; } public override bool Equals(object obj) { return this.Equals(obj as EntityBase); } #endregion } public class Author : EntityBase { public Author() { } } public class Book : EntityBase { public Book() { } } 

De esta manera, tengo el método reutilizable Equals () que funciona de la caja para todas mis clases derivadas.