2013-01-31 6 views
8

Betrachte T = string.Wie funktioniert EqualityComparer <T> .Default intern?

Ich bin gespannt, ob es nutzt so etwas wie: typeof(EqualityComparer<T>).GetInterface("IEqualityComparer<T>");

Irgendwelche Vorschläge ..

+0

Warum sollte 'GetInterface' gesagt werden, um das' System.Type'-Objekt für die Schnittstelle zu erhalten, die es selbst implementiert? Wie wäre das nützlich? Es könnte einfach 'typeof (IEqualityComparer )' sagen, wenn es diesen Typ somhow benötigt, aber das braucht es nicht. Es muss eine Instanz von EqualityComparer zurückgeben, die wir verwenden können. Da die Klasse "abstrakt" ist, muss eine Instanz einer nicht abstrakten abgeleiteten Klasse erstellt und zurückgegeben werden. Aber vielleicht fragen Sie wirklich, wie sich das zurückgegebene Objekt verhält? (Zumindest habe ich das unten beantwortet.) –

Antwort

9

mit freundlicher Genehmigung von Reflektor:

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

So wie Sie sehen können, wenn T = string es wird zurückkehren GenericEqualityComparer<string>.

+0

Beat mich dazu: P –

+2

Ich weiß nicht, ob das hilfreich ist. Es zeigt, welche nicht-öffentliche Klasse hinter der Szene verwendet wird, aber es gibt keine Informationen darüber, wie die nicht-öffentliche 'GenericEqualityComparer ' Klasse funktioniert. Wen kümmert es also, was die konkrete Realisierung der abstrakten Klasse heißt? –

2

EqualityComparer<T>.Default Werke die virtual Methoden Equals(object) und GetHashCode() Aufruf, die von System.Object definiert sind, aber durch T werden oder kann nicht außer Kraft gesetzt werden.

Beachten Sie, dass, da die Metoden virtual sind, eine Implementierung einer abgeleiteten Klasse als T verwendet werden kann. Zum Beispiel:

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

wird true zurückkehren, auch wenn

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

und

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

beide Rück false.

In dem Fall, in dem Tstring ist, überlädt die Klasse System.String die beiden fraglichen Methoden und verwendet einen ordinalen Vergleich. In diesem Fall sollte es also System.StringComparer.Ordinal entsprechen. Und natürlich string ist eine sealed Klasse, so könnte keine andere Klasse von string abgeleitet werden und Equals und GetHashCode auf eine seltsame Weise übersteuern.

+1

Auch - Der Vorteil ist, dass zuerst überprüft, ob T implementiert IEquatable und wenn ja, ruft diese Implementierung stattdessen, Vermeidung der Boxen Overhead. Dies ist besonders nützlich in generischen Methoden: 'statische bool Foo (T x, T y) { bool gleiche = EqualityComparer .Default.Equals (x, y);' –

Verwandte Themen