Rozważmy T = string.W jaki sposób EqualityComparer <T> .Default działa wewnętrznie?
Jestem ciekawy, czy używa coś takiego: typeof(EqualityComparer<T>).GetInterface("IEqualityComparer<T>");
wszelkie sugestie ..
Rozważmy T = string.W jaki sposób EqualityComparer <T> .Default działa wewnętrznie?
Jestem ciekawy, czy używa coś takiego: typeof(EqualityComparer<T>).GetInterface("IEqualityComparer<T>");
wszelkie sugestie ..
Dzięki uprzejmości 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>();
}
Więc jak widać, jeśli T = łańcuch powróci GenericEqualityComparer<string>
.
Zadzwoń do mnie: P –
Nie wiem, czy to jest pomocne. Pokazuje, z której klasy niepopularnej korzysta się za sceną, ale nie zawiera informacji o tym, jak działa niepubliczna klasa "GenericEqualityComparer
EqualityComparer<T>.Default
prace poprzez wywołanie metody virtual
Equals(object)
i GetHashCode()
które są zdefiniowane przez System.Object
ale może lub nie może być przesłonięta przez T
.
Należy pamiętać, że ze względu na metody są virtual
, można zastosować implementację bardziej pochodnej klasy niż T
. Na przykład:
EqualityComparer<object>.Default
.Equals(new Uri("http://example.com/"), new Uri("http://example.com/"))
powróci true
, nawet jeśli
Object.ReferenceEquals(new Uri("http://example.com/"), new Uri("http://example.com/"))
i
(object)new Uri("http://example.com/") == (object)new Uri("http://example.com/")
zarówno powrócić false
.
W przypadku, gdy T
jest string
, klasa System.String
przeciąża dwie metody i stosuje porównanie porządkowe. Tak więc w tym przypadku powinien być równoważny z System.StringComparer.Ordinal
. I oczywiście string
jest klasą sealed
, więc żadna inna klasa nie mogłaby pochodzić z string
i zastąpić Equals
i GetHashCode
w dziwny sposób.
Również - Zaleta polega na tym, że najpierw sprawdza, czy T implementuje 'IEquatable
Po co miałoby mówić 'GetInterface', aby uzyskać obiekt' System.Type' dla interfejsu, który sam implementuje? Jak byłoby to przydatne? Mógłby po prostu powiedzieć 'typeof (IEqualityComparer)' jeśli potrzebował tego typu, ale nie potrzebuje tego. Musi zwrócić instancję 'EqualityComparer ', której możemy użyć. Ponieważ klasa jest "abstrakcyjna", wiąże się to z tworzeniem instancji niektórych nie abstrakcyjnych klas pochodnych i zwracaniem tego. Ale może naprawdę pytasz, jak zachowuje się zwracany obiekt? (Przynajmniej tak odpowiedziałem poniżej.) –