为什么检查开放泛型类型的相等性不一致?
Why is checking equality of open generic types inconsistent?
出于某种原因:
typeof(Dictionary<string,string>).GetGenericTypeDefinition()
.GetInterfaces()
.Contains(typeof(IDictionary<,>))
是false
但是这个:
typeof(Dictionary<string,string>).GetInterfaces()
.Any(i => i.IsGenericType
&& i.GetGenericTypeDefinition() == typeof(IDictionary<,>))
是 true
,即使它们在具有相同 GUID 的调试器中显示为 IDictionary'2
。
在第一个示例中,接口数组中的 [0]
是 IDictionary'2
,如果我直接将其与 typeof
(没有 .Contains(...)
)或 ==
或 .Equals(...)
甚至 .IsAssignableFrom(...)
都是相同的结果。
拜托,有人告诉我为什么!
因为从.GetGenericTypeDefinition().GetInterfaces()
返回的接口不是“通用类型定义”(它们的IsGenericTypeDefinition
是false
),所以它们不能严格等于IDictionary<,>
(这是一个泛型类型定义,IsGenericTypeDefinition
即 true
)。
第二块代码从接口钻取到它们的通用类型定义,让您进行比较。
关于所发生情况的一个简单示例:
class MyDictionary<TKey2, TValue2> : IDictionary<TKey2, TValue2>
{
public TValue2 this[TKey2 key] { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public ICollection<TKey2> Keys => throw new NotImplementedException();
public ICollection<TValue2> Values => throw new NotImplementedException();
public int Count => throw new NotImplementedException();
public bool IsReadOnly => throw new NotImplementedException();
public void Add(TKey2 key, TValue2 value) => throw new NotImplementedException();
public void Add(KeyValuePair<TKey2, TValue2> item) => throw new NotImplementedException();
public void Clear() => throw new NotImplementedException();
public bool Contains(KeyValuePair<TKey2, TValue2> item) => throw new NotImplementedException();
public bool ContainsKey(TKey2 key) => throw new NotImplementedException();
public void CopyTo(KeyValuePair<TKey2, TValue2>[] array, int arrayIndex) => throw new NotImplementedException();
public IEnumerator<KeyValuePair<TKey2, TValue2>> GetEnumerator() => throw new NotImplementedException();
public bool Remove(TKey2 key) => throw new NotImplementedException();
public bool Remove(KeyValuePair<TKey2, TValue2> item) => throw new NotImplementedException();
public bool TryGetValue(TKey2 key, out TValue2 value) => throw new NotImplementedException();
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
}
然后:
var interfaces = typeof(MyDictionary<string, string>).GetGenericTypeDefinition().GetInterfaces();
var idict1 = interfaces[0];
var idict2 = idict1.GetGenericTypeDefinition();
Console.WriteLine(idict1);
Console.WriteLine(idict2);
结果:
System.Collections.Generic.IDictionary`2[TKey2,TValue2] <-- This is what you get with GetInterfaces()
System.Collections.Generic.IDictionary`2[TKey,TValue] <-- And this is the generic type definition
很明显 idict1
不可能是 IDictionary<,>
,因为它是 IDictionary<TKey2, TValue2>
出于某种原因:
typeof(Dictionary<string,string>).GetGenericTypeDefinition()
.GetInterfaces()
.Contains(typeof(IDictionary<,>))
是false
但是这个:
typeof(Dictionary<string,string>).GetInterfaces()
.Any(i => i.IsGenericType
&& i.GetGenericTypeDefinition() == typeof(IDictionary<,>))
是 true
,即使它们在具有相同 GUID 的调试器中显示为 IDictionary'2
。
在第一个示例中,接口数组中的 [0]
是 IDictionary'2
,如果我直接将其与 typeof
(没有 .Contains(...)
)或 ==
或 .Equals(...)
甚至 .IsAssignableFrom(...)
都是相同的结果。
拜托,有人告诉我为什么!
因为从.GetGenericTypeDefinition().GetInterfaces()
返回的接口不是“通用类型定义”(它们的IsGenericTypeDefinition
是false
),所以它们不能严格等于IDictionary<,>
(这是一个泛型类型定义,IsGenericTypeDefinition
即 true
)。
第二块代码从接口钻取到它们的通用类型定义,让您进行比较。
关于所发生情况的一个简单示例:
class MyDictionary<TKey2, TValue2> : IDictionary<TKey2, TValue2>
{
public TValue2 this[TKey2 key] { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public ICollection<TKey2> Keys => throw new NotImplementedException();
public ICollection<TValue2> Values => throw new NotImplementedException();
public int Count => throw new NotImplementedException();
public bool IsReadOnly => throw new NotImplementedException();
public void Add(TKey2 key, TValue2 value) => throw new NotImplementedException();
public void Add(KeyValuePair<TKey2, TValue2> item) => throw new NotImplementedException();
public void Clear() => throw new NotImplementedException();
public bool Contains(KeyValuePair<TKey2, TValue2> item) => throw new NotImplementedException();
public bool ContainsKey(TKey2 key) => throw new NotImplementedException();
public void CopyTo(KeyValuePair<TKey2, TValue2>[] array, int arrayIndex) => throw new NotImplementedException();
public IEnumerator<KeyValuePair<TKey2, TValue2>> GetEnumerator() => throw new NotImplementedException();
public bool Remove(TKey2 key) => throw new NotImplementedException();
public bool Remove(KeyValuePair<TKey2, TValue2> item) => throw new NotImplementedException();
public bool TryGetValue(TKey2 key, out TValue2 value) => throw new NotImplementedException();
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
}
然后:
var interfaces = typeof(MyDictionary<string, string>).GetGenericTypeDefinition().GetInterfaces();
var idict1 = interfaces[0];
var idict2 = idict1.GetGenericTypeDefinition();
Console.WriteLine(idict1);
Console.WriteLine(idict2);
结果:
System.Collections.Generic.IDictionary`2[TKey2,TValue2] <-- This is what you get with GetInterfaces()
System.Collections.Generic.IDictionary`2[TKey,TValue] <-- And this is the generic type definition
很明显 idict1
不可能是 IDictionary<,>
,因为它是 IDictionary<TKey2, TValue2>