尽管 John Wu 就类型定义和实际类型之间的差异写了一个很好的答案,但我认为它并不能完全回答 OP 中提出的问题/问题。
有什么方法可以检查两个open type之间的关系,
还是关系只存在于封闭类型上?
首先,关系永远存在;每个List<> 始终是IEnumerable<>,正如您在List<T> 类型的定义中看到的那样:
public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, ...
但这并不能回答您的第二个问题,如果有办法检查两种类型之间是否存在这种关系。你会认为IsAssignableFrom 方法可以用来检查类型 open 类型之间是否存在关系,但你不能。为什么?让我们在IsAssignableFromfunction的文档中找出答案:
Type.IsAssignableFrom (Type c) 如果以下任一条件为真,则返回真:
- c 和当前实例代表相同的类型。
c 直接或间接从当前
实例。 c 直接从当前实例派生,如果它
从当前实例继承; c 是间接派生自
当前实例,如果它继承自一个或多个连续
从当前实例继承的类。
当前实例是c实现的接口。
c是泛型类型参数,当前实例代表
c.的约束之一。
如果这些条件都不为真,或者 c 为空,则为假。
在您的情况下,上述条件都不会导致 true,因为:(1) 它们不是同一类型。 (2) 它们不能相互派生,因为它们是开放类型:它们的泛型类型参数是未知的 (unknown != unknown)。 List<> 实现封闭的 IEnumerable<T> 类型,而不是开放的 IEnumerable<> 类型 (3)。它们不是泛型类型参数 (4)。
要确定两个泛型类型是否存在关系,您需要检查它们的 type definitions(以及它们的嵌套接口/基类型)并验证它们是否存在关系:
public static bool IsAssignableToOpenGenericType(Type givenType, Type genericType)
{
var interfaceTypes = givenType.GetInterfaces();
foreach (var it in interfaceTypes)
{
if (it.IsGenericType && it.GetGenericTypeDefinition() == genericType)
return true;
}
if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
return true;
Type baseType = givenType.BaseType;
if (baseType == null) return false;
return IsAssignableToGenericType(baseType, genericType);
}
(source)
将导致:
var typ1 = typeof(List<>);
var typ2 = typeof(IEnumerable<>);
// true, List<>'s type definition contains an IEnumerable<>
Console.WriteLine(IsAssignableToOpenGenericType(typ1, typ2));
// false, IEnumerable<>'s type definition does not contain List<>
Console.WriteLine(IsAssignableToOpenGenericType(typ2, typ1));