2012-07-10 8 views
7

Como mi cobertura de prueba (unidad) todavía es bastante baja, desafortunadamente, tengo que encontrar muchos errores por las malas. Por lo tanto, durante la refactorización, confío mucho en la verificación de tipos del compilador de C#.Type-safe Igual()

Hoy solucioné un error introducido durante la refactorización al omitir una línea con x.Equals(aThingWrappingOriginalThing). Como es bool Equals(object T), el compilador no se quejó. Sin embargo, el 90% del tiempo que uso Equals() directamente (en lugar de BCL), intento comparar lógicamente objetos del mismo tipo.

Ahora me pregunto por qué nunca he visto a alguien promocionando una versión segura de tipo de Equals() para tales situaciones (en C#). ¿Hay una mejor práctica para esto?

Estoy tentado a usar un método de extensión para aquellas comparaciones, así:

public static bool SafeEquals<T>(this T a, T b) 
{ 
    if (a == null) return b == null; 
    return a.Equals(b); 
} 
public static bool SafeEquals<X>(this IEquatable<X> a, IEquatable<X> b) 
{ 
    if (a == null) return b == null; 
    return a.Equals(b); 
} 

Podrían estos pueden optimizar?

Aquí es la única entrada en el blog sobre el tema que he encontrado, para Java: http://rickyclarkson.blogspot.com/2006/12/making-equalsobject-type-safe.html

+0

Aquí hay algunos antecedentes sobre el tema: http://blogs.msdn.com/b/ericlippert/archive/2009/04/09/double-your-dispatch-double-your-fun.aspx – Vlad

Respuesta

5

Usted está buscando

EqualityComparer<T>.Default.Equals(x,y); 

esto apoya IEquatable<T> (si se aplica), de lo contrario utiliza el boxeo potencialmente Equals(object); admite clases y estructuras, con comportamiento nulo esperado para ambos, incluido soporte para Nullable<T> (sin boxeo).

+0

Gracias, suena genial. ¿Duele el rendimiento para envolverlo en un método de extensión? ¿Será inline? – Equalizer

+0

@Equalizer son métodos de extensión llamada estática, entonces: no realmente, no. Es poco probable que esté inclinado porque .Default es una instancia de cualquiera de una serie de implementaciones concretas, según la estrategia que se utilizará. La decisión/reflección solo se realiza una vez por T, por lo que se almacena en caché, pero no en línea. –

2

Lo que veo me parece bueno.

Mis 2 centavos: Creo que sería más sencillo saltarse los controles nulos, y usar esto:

public static bool SafeEquals<T>(this T a, T b) 
{ 
    return object.Equals(a, b); 
} 

Hay muy pocos casos en los que que se desviaría de comportamiento previsto. Uno de ellos es cuando Equals devuelve falso cuando ambos objetos son el mismo objeto (lo que nunca debería ocurrir de todos modos).

Como referencia, aquí está el descompilado object.Equals, por lo que puede ver por sí mismo lo que sucede.

public static bool Equals(object objA, object objB) 
{ 
    return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB))); 
} 
+0

'Objeto. Iguales' comprueban si ambos apuntan a los mismos datos en el montón, no si son iguales. –

+0

@Kendall la primera implementación aquí es solo un envoltorio alrededor del objeto. Iguales, para eso, ¿por qué no simplemente dejar que el consumidor llame a object.Equals para todo lo que vale – Jason

+0

@ColeJohnson Tal vez de forma predeterminada. Pero hay una diferencia entre 'Equals' y' ReferenceEquals' –