2011-02-04 15 views
18

Ci sono diversi posti in BCL dove si può fare uso di IEqualityComparer. Come Enumerable.Contains o Dictionary Constructor. Posso fornire il mio comparatore se non sono soddisfatto dello default.Esiste qualche tipo di "ReferenceComparer" in .NET?

A volte voglio sapere se la raccolta contiene quello stesso oggetto a cui mi riferisco. Non quello che è considerato "uguale" in nessun altro significato.
La domanda è: se esiste un confronto di uguaglianza standard nel BCL che si basa solo sul metodo ReferenceEquals?

Quello che io ho scritto è questo:

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); 
    } 
} 

non ho la prova a fondo, né sacco considerati di scenari, ma sembra di fare Enumerable.Contains e Dictionary abbastanza felice.

+2

È un peccato che tutte queste raccolte siano state scritte in modo Java, richiedendo di scrivere una classe che implementa un'interfaccia specifica. Se solo ti permettessero di passare in un delegato per specificare l'operatore di confronto, potresti passare direttamente "oggetto.ReferenceEquals". Immagino sia perché sono necessari due metodi (confronto e codice hash). –

+0

A quanto ho capito, però, la controparte Java di 'IEqualityComparer' non ha un' GetHashCode', quindi * potrebbe * essere implementato come delegato in Java se i delegati supportati da Java. – Gabe

+1

@Ben guarda la risposta di orip: http: // stackoverflow.it/questions/98033/wrap-a-delegate-in-an-iequalitycomparer/1239337 # 1239337 –

risposta

17

Per quanto ne so, il BCL non espone alcun tipo pubblico che implementa IEqualityComparer<T> con riferimento-uguaglianza a partire da. NET 4.0.

Tuttavia, non sembrano esserci un mazzo di tipi interni che fanno questo, come:

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

ho preso uno sguardo alle implementazioni di questi due tipi con riflettore, e sarete felici di sapere che entrambi sembrano essere implementato in un modo che è praticamente identico al tuo, se non che non usano l'inizializzazione pigra per l'istanza statica (la creano nel costruttore statico per il tipo).

L'unico "problema" possibile con la tua implementazione è che l'inizializzazione pigra non è thread-safe, ma poiché le istanze sono "economiche" e non si applicano a nessuno stato, ciò non dovrebbe creare eventuali bug o problemi di prestazioni importanti. Se si desidera che imponga il modello singleton, è necessario farlo correttamente.

+0

Grazie per aver menzionato il mio errore di inizializzazione pigro. Per questa classe sembra significativo inizializzare l'istanza nel costruttore statico. Tuttavia, grazie a te, non farò lo stesso errore da nessun'altra parte. –

+0

@ alpha-mouse: Saluti. Direi che non mi sentirei obbligato a creare una classe sicura per il thread solo per il gusto di farlo, a meno che non intenda * usarlo * in un modo che lo richiede. – Ani

+0

C'è anche 'System.Data.Entity.Infrastructure.ObjectReferenceEqualityComparer'. –

2

Finisco per utilizzare questa soluzione anche perché non sono riuscito a trovare alcuna soluzione alternativa.

Per correggere l'implementazione non thread-safe, è possibile utilizzare facilmente un inizializzatore statico.

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

(spiacente per la risposta, invece di un commento alla discussione up-votato, ho un nuovo account con diritti di commento, ancora).

Problemi correlati