List <>和IEnumerable <> open类型之间的关系

Yon*_*onF 20 .net c#

开放类型List<>IEnumerable<>?之间有什么关系吗?

例:

var type1 = typeof(List<>);
var type2 = typeof(IEnumerable<>);

//return false
type2.IsAssignableFrom(type1);
Run Code Online (Sandbox Code Playgroud)

有没有任何方法可以检查两种开放类型之间的关系,或者关系只存在于封闭类型上?

Joh*_* Wu 19

List<>IEnumerable<>不是类型; 它们是类型定义.因此,询问一个人是否可以转让给另一个人是没有意义的.两者都不能分配给.例如,您无法声明变量List<> a = null- 您将收到编译错误"意外使用未绑定的通用名称".

指定type参数时,类型定义将成为泛型类型.此时,它是一种类型,可以分配给.所以例如List<string>可以分配给IEnumerable<string>.

如果您有一个类型定义并且想要进行类型兼容性检查,只需使用<object>(或者如果存在类型约束,则使用合适的类型),而不是<>:

var type1 = typeof(List<object>);
var type2 = typeof(IEnumerable<object>);

//returns true
type2.IsAssignableFrom(type1);
Run Code Online (Sandbox Code Playgroud)


Jev*_*sen 16

尽管John Wu对类型定义与实际类型之间的差异写了一个很好的答案,但我认为它并没有完全回答OP中提出的问题/问题.

有没有任何方法可以检查两种开放类型之间的关系,或者关系只存在于封闭类型上?

首先,这种关系始终存在; 每个List<>都是一个IEnumerable<>,你可以在List<T>类型的定义中看到:

public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, ...

但是如果有办法检查两种类型之间是否存在这种关系,那么这不能回答你的第二个问题.您可能会认为该IsAssignableFrom方法可用于检查类型打开类型之间是否存在关系,但您不能.为什么?让我们在IsAssignableFrom 函数的文档中找到:

Type.IsAssignableFrom(Type c)如果满足以下任一条件,则返回true:

  1. c和当前实例表示相同的类型.
  2. c直接或间接地从当前实例派生.如果它从当前实例继承,则直接从当前实例派生; 如果c继承自从当前实例继承的一个或多个类的连续,则c从当前实例间接派生.

  3. 当前实例是c实现的接口.

  4. c是泛型类型参数,当前实例表示c的约束之一.

如果这些条件均不为真,或者c为null,则为false.

在您的情况下,上述条件都不会导致如下:(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);
}
Run Code Online (Sandbox Code Playgroud)

(资源)

将导致:

    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));
Run Code Online (Sandbox Code Playgroud)