简体   繁体   中英

How does EqualityComparer<T>.Default works internally?

Consider T = string.

I'm curious if it uses something like: typeof(EqualityComparer<T>).GetInterface("IEqualityComparer<T>");

Any suggestions..

Courtesy of Reflector:

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 as you can see if T = string it will return GenericEqualityComparer<string> .

EqualityComparer<T>.Default works by calling the virtual methods Equals(object) and GetHashCode() which are defined by System.Object but may or may not be overridden by T .

Note that since the metods are virtual , an implementation of a more derived class than T may be used. For example:

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

will return true , even if

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

and

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

both return false .

In the case where T is string , the class System.String overloads the two methods in question and use an ordinal comparison. Thus in this case it should be equivalent to System.StringComparer.Ordinal . And of course string is a sealed class, so no other class could derive from string and override Equals and GetHashCode in some strange way.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM