2010-03-19 15 views
30

Simplemente no entiendo esto - ¿Qué le compra exactamente IEquatable?Cuándo usar IEquatable Y por qué

La única razón por la que puedo ver que es útil es cuando se crea un tipo genérico y se obliga a los usuarios a implementar y escribir un buen método de igualdad.

¿Qué me falta

+1

Se te salve boxeo manejo/unboxing. Aquí la explicación buena y sencilla de que: http: //www.codeproject.com/Articles/20592/Implementing-IEquatable-Properly – Jviaches

Respuesta

32

Desde el MSDN:

La interfaz de IEquatable(T) se utiliza por colección genérica objetos tales como Dictionary(TKey, TValue), List(T), y LinkedList(T) cuando se prueba por la igualdad en tales métodos como Contains, IndexOf, LastIndexOf, y Remove.

La aplicación IEquatable<T> requerirá una menos fundido para estas clases y como resultado será un poco más rápido que el método estándar object.Equals que sería utilizado de otra forma. Como ejemplo, vea la diferente implementación de los dos métodos:

public bool Equals(T other) 
{ 
    if (other == null) 
    return false; 

    return (this.Id == other.Id); 
} 

public override bool Equals(Object obj) 
{ 
    if (obj == null) 
    return false; 

    T tObj = obj as T; // The extra cast 
    if (tObj == null) 
    return false; 
    else 
    return this.Id == tObj.Id; 
} 
+3

¿Alguien sabe qué sucede si no implementa iequtalable cuando usa colecciones genéricas? –

+1

@ChloeRadshaw utilizará una referencia igual para los tipos de referencia a continuación. – Cornelius

+1

Funcionará con los tipos anteriores sin implementar IEquatable ; simplemente usará el valor predeterminado Equals() en su lugar. Dicho esto, suena como que va a utilizar IEquatable si está disponible, y evitar el boxeo/unboxing que dibujó Freyling menciona. – Doug

11

utilizo IEquatable<T> mucho, aunque desde un punto de vista puramente técnico, que en realidad no me dan ningún beneficio en particular. Anular System.Object.Equals puede proporcionarle la misma funcionalidad.

Sin embargo, me gusta el explicitud de la implementación de IEquatable<T>. Utilizo los conceptos de Entidades Objetos de valor desde Domain-Driven Design bastante, y uso IEquatable<T> particularmente para objetos de valor, simplemente porque indica que un tipo tiene igualdad bien definida.

+7

No hay que olvidar que el uso de IEquatable significará que usted no tendrá que soportar el boxeo/unboxing que obtienes con System.Object.Equals. Sólo –

+3

tipos sellados deben implementar '' IEquatable . Si '' IEquatable hace nada que no sea la cadena de 'Object.equals (Object)', cualquier tipo derivado 'XDerived' que redefine la igualdad debe volver a aplicar' 'IEquatable y lo han echado de su argumento de' XDerived'. De lo contrario, se generaría un objeto que no se comportará correctamente, como p. Ej. un 'Diccionario '. – supercat

23

Me sorprende que la razón más importante no se mencione aquí.

IEquatable<> se introdujo principalmente para estructuras por dos razones:

  1. Para los tipos de valor (leer estructuras) la no genérico Equals(object) requiere boxeo. IEquatable<> permite que una estructura implemente un método fuertemente tipado Equals para que no se requiera ningún boxeo.

  2. Para estructuras, la implementación predeterminada de Object.Equals(Object) (que es la versión reemplaza en System.ValueType) realiza una comprobación de igualdad de valor mediante el uso de la reflexión para comparar los valores de cada campo en el tipo. Cuando un implementador anula el método virtual Equals en una estructura, el propósito es proporcionar un medio más eficiente para realizar la comprobación de igualdad de valores y, opcionalmente, basar la comparación en algún subconjunto del campo o las propiedades de la estructura.

Ambos mejoran el rendimiento.

Los tipos de referencia (clases de lectura) no se benefician tanto. La implementación IEquatable<> le permite evitar un reparto de System.Object, pero esa es una ganancia muy trivial.Todavía me gusta que IEquatable<> se implemente para mis clases, ya que lógicamente hace que el intento sea explícito.

0

Además de las otras respuestas, esta es una muy buena razón para implementar IEquatable<T> (y obviamente anulando Equals(object) también) para los tipos de valores. Basta con mirar el código predeterminado ValueType.Equals(object) que recibe otra llamada. Es un asesino de rendimiento absoluto que introduce el boxeo, la evaluación del tipo y finalmente se retrae en la reflexión si alguno de los campos son tipos de referencia.

public override bool Equals(object obj) 
{ 
    if (obj == null) 
    { 
     return false; 
    } 
    RuntimeType type = (RuntimeType) base.GetType(); 
    RuntimeType type2 = (RuntimeType) obj.GetType(); 
    if (type2 != type) 
    { 
     return false; 
    } 
    object a = this; 
    if (CanCompareBits(this)) 
    { 
     return FastEqualsCheck(a, obj); 
    } 
    FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); 
    for (int i = 0; i < fields.Length; i++) 
    { 
     object obj3 = ((RtFieldInfo) fields[i]).UnsafeGetValue(a); 
     object obj4 = ((RtFieldInfo) fields[i]).UnsafeGetValue(obj); 
     if (obj3 == null) 
     { 
      if (obj4 != null) 
      { 
       return false; 
      } 
     } 
     else if (!obj3.Equals(obj4)) 
     { 
      return false; 
     } 
    } 
    return true; 
} 

En ciertos escenarios (como el uso del tipo de valor como clave en un diccionario) se puede asesinar el rendimiento de una sola falta.

Cuestiones relacionadas