2011-02-04 14 views
18

Hay varios lugares en BCL donde se puede hacer uso de IEqualityComparer. Como Enumerable.Contains o Dictionary Constructor. Puedo proporcionar mi comparador si no estoy satisfecho con el default.¿Hay algún tipo de "ReferenceComparer" en .NET?

A veces quiero saber si la colección contiene ese mismo objeto al que me he referido. No es el que se considera "igual" en ningún otro significado.
La pregunta es: si existe un comparador de igualdad estándar en el BCL que se basa únicamente en el método ReferenceEquals?

El que escribí a mí mismo es la siguiente:

class ReferenceComparer<T> : IEqualityComparer<T> where T : class 
{ 
    private static ReferenceComparer<T> m_instance; 

    public static ReferenceComparer<T> Instance 
    { 
     get 
     { 
      return m_instance ?? (m_instance = new ReferenceComparer<T>()); 
     } 
    } 

    public bool Equals(T x, T y) 
    { 
     return ReferenceEquals(x, y); 
    } 

    public int GetHashCode(T obj) 
    { 
     return RuntimeHelpers.GetHashCode(obj); 
    } 
} 

no he probado a fondo ni se considerará una gran cantidad de escenarios, pero parece que tiene Enumerable.Contains y Dictionary muy feliz.

+2

Desafortunadamente, todas estas colecciones están escritas de forma similar a Java, lo que requiere que escriba una clase que implemente una interfaz específica. Si solo le permitieran pasar un delegado para especificar el operador de comparación, podría pasar 'object.ReferenceEquals' directamente. Supongo que es porque se necesitan dos métodos (comparación y hashcode). –

+0

Según tengo entendido, la contraparte de Java para 'IEqualityComparer' no tiene' GetHashCode', por lo que * podría * implementarse como delegado en Java si los delegados admitidos por Java. – Gabe

+1

@Ben mira la respuesta de orip: http: // stackoverflow.com/questions/98033/wrap-a-delegate-in-an-iequalitycomparer/1239337 # 1239337 –

Respuesta

17

Hasta donde yo sé, el BCL no expone ningún tipo público que implemente IEqualityComparer<T> con reference-equality a partir de .NET 4.0.

Sin embargo, no parecen ser un manojo de tipos internos que hacen esto, tales como:

  • System.Dynamic.Utils.ReferenceEqualityComparer<T> (en System.Core)
  • System.Xaml.Schema.ReferenceEqualityComparer<T> (en System.Xaml).

Me tomó un vistazo a las implementaciones de estos dos tipos con reflector, y estarás feliz de saber que ambos parecen estar implementado de una manera que es prácticamente idéntica a la suya, excepto que no usan la inicialización diferida para la instancia estática (lo crean en el constructor estático para el tipo).

El único 'problema' posible que puedo pensar con su implementación es que la inicialización lenta no es segura para subprocesos, pero dado que las instancias son 'baratas' y no se mantienen en ningún estado, eso no debería crear cualquier error o mayor problema de rendimiento. Si desea aplicar el patrón singleton sin embargo, tendrá que hacerlo correctamente.

+0

Gracias por mencionar mi error de inicialización perezosa. Para esta clase, parece significativo inicializar la instancia en el constructor estático. Sin embargo, gracias a ti, no cometeré el mismo error en ningún otro lado. –

+0

@ alpha-mouse: Saludos. Diría que no me sentiría obligado a hacer una clase segura para subprocesos solo por el mero hecho de hacerlo, a menos que pretenda * usar * de una manera que lo requiera. – Ani

+0

También hay 'System.Data.Entity.Infrastructure.ObjectReferenceEqualityComparer'. –

2

Termino utilizando esta solución también, ya que no pude encontrar ninguna solución.

Para solucionar la implementación no segura de subprocesos, puede usar fácilmente un iniciador de sesión estático.

public static ReferenceComparer<T> Instance => new ReferenceComparer<T>(); 

(lo siento por la respuesta en lugar de un comentario al hilo hacia arriba-votado, tengo una nueva cuenta con ningún derecho de comentarios, todavía).

Cuestiones relacionadas