2013-01-31 12 views
8

Considera T = stringa.In che modo EqualityComparer <T> .Default funziona internamente?

Sono curioso di sapere se si utilizza qualcosa come: typeof(EqualityComparer<T>).GetInterface("IEqualityComparer<T>");

Qualche suggerimento ..

+0

Perché dire 'GetInterface' per ottenere l'oggetto' System.Type' per l'interfaccia che implementa da solo? Come sarebbe utile? Potrebbe semplicemente dire 'typeof (IEqualityComparer )' se fosse necessario digitare quel tipo, ma non è necessario. È necessario restituire un'istanza di 'EqualityComparer ' che possiamo usare. Poiché la classe è 'abstract', ciò comporta la creazione di un'istanza di una classe derivante non astratta e la sua restituzione. Ma forse chiedi veramente a cosa si comporta l'oggetto restituito? (Almeno era quello che ho risposto di seguito.) –

risposta

9

Per gentile concessione di riflettore:

public static EqualityComparer<T> Default 
{ 
    get 
    { 
     EqualityComparer<T> defaultComparer = EqualityComparer<T>.defaultComparer; 
     if (defaultComparer == null) 
     { 
      defaultComparer = EqualityComparer<T>.CreateComparer(); 
      EqualityComparer<T>.defaultComparer = defaultComparer; 
     } 
     return defaultComparer; 
    } 
} 

private static EqualityComparer<T> CreateComparer() 
{ 
    RuntimeType c = (RuntimeType) typeof(T); 
    if (c == typeof(byte)) 
    { 
     return (EqualityComparer<T>) new ByteEqualityComparer(); 
    } 
    if (typeof(IEquatable<T>).IsAssignableFrom(c)) 
    { 
     return (EqualityComparer<T>) RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType) typeof(GenericEqualityComparer<int>), c); 
    } 
    if (c.IsGenericType && (c.GetGenericTypeDefinition() == typeof(Nullable<>))) 
    { 
     RuntimeType type2 = (RuntimeType) c.GetGenericArguments()[0]; 
     if (typeof(IEquatable<>).MakeGenericType(new Type[] { type2 }).IsAssignableFrom(type2)) 
     { 
      return (EqualityComparer<T>) RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType) typeof(NullableEqualityComparer<int>), type2); 
     } 
    } 
    if (c.IsEnum && (Enum.GetUnderlyingType(c) == typeof(int))) 
    { 
     return (EqualityComparer<T>) RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType) typeof(EnumEqualityComparer<int>), c); 
    } 
    return new ObjectEqualityComparer<T>(); 
} 

Quindi, come si può vedere se T = stringa tornerà GenericEqualityComparer<string>.

+0

Mi picchia: P –

+2

Non so se questo è utile. Mostra quale classe non pubblica viene utilizzata dietro la scena, ma non fornisce informazioni su come funziona la classe 'GenericEqualityComparer ' non pubblica. Quindi a chi importa cosa la realizzazione concreta della classe astratta è _named_? –

2

EqualityComparer<T>.Default opere chiamando i metodi virtualEquals(object) e GetHashCode() che sono definiti da System.Object ma può o non può essere sovrascritto dalle T.

Si noti che poiché i metodi sono virtual, è possibile utilizzare un'implementazione di una classe più derivata di T. Ad esempio:

EqualityComparer<object>.Default 
    .Equals(new Uri("http://example.com/"), new Uri("http://example.com/")) 

tornerà true, anche se

Object.ReferenceEquals(new Uri("http://example.com/"), new Uri("http://example.com/")) 

e

(object)new Uri("http://example.com/") == (object)new Uri("http://example.com/") 

entrambi restituiscono false.

Nel caso in cui T è string, classe System.String sovraccarica i due metodi in questione e utilizzare un confronto ordinale. Quindi in questo caso dovrebbe essere equivalente a System.StringComparer.Ordinal. E ovviamente string è una classe sealed, quindi nessun'altra classe potrebbe derivare da string e sostituire Equals e GetHashCode in qualche modo strano.

+1

Inoltre: il vantaggio è che verifica innanzitutto se T implementa 'IEquatable ' e, in caso affermativo, chiama invece l'implementazione , evitando il sovraccarico di boxe. Ciò è particolarmente utile nei metodi generici: 'bool statico Foo (T x, T y) { bool same = EqualityComparer .Default.Equals (x, y);' –

Problemi correlati