【问题标题】:Relation between List<> and IEnumerable<> open typeList<> 和 IEnumerable<> 开放类型的关系
【发布时间】:2018-11-20 07:04:20
【问题描述】:

开放类型List&lt;&gt;IEnumerable&lt;&gt;之间有什么关系吗?

例子:

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

//return false
type2.IsAssignableFrom(type1);

有没有办法检查两个开放类型之间的关系,或者关系只存在于封闭类型上?

【问题讨论】:

  • 请注意,每个通用参数都是唯一的。这意味着List&lt;T(from List&lt;T&gt;)&gt; 实现IEnumerable&lt;T(from List&lt;T&gt;)&gt; 但不是IEnumerable&lt;T(from IEnumerable&lt;T&gt;)&gt;
  • 你到底想在这里完成什么?如果我们知道您最初尝试解决的问题是什么,我们或许可以提供其他不依赖于比较开放泛型类型的解决方案。
  • 很抱歉进行了激烈的编辑,但我认为只有前 3 行中表达的问题才是这里真正有趣的部分。您试图对其余代码执行的操作非常不清楚,您必须按照@Damien_The_Unbeliever 的说明进一步解释。
  • @PetSerAl 如何理解每个泛型参数是唯一的?您的意思是在 List 中键入 int 并且 IEnumerable 是“不同的”吗?

标签: c# .net


【解决方案1】:

List&lt;&gt;IEnumerable&lt;&gt; 不是类型;他们是type definitions。因此,询问一个是否可以分配给另一个是没有意义的。两者都不能分配给。例如,您不能声明变量List&lt;&gt; a = null - 您将收到编译错误“意外使用未绑定的通用名称。”

当您指定类型参数时,类型定义将成为泛型类型。此时,它是一种类型,可以分配给它。例如,List&lt;string&gt; 可以分配给IEnumerable&lt;string&gt;

如果您有类型定义并且想要进行类型兼容性检查,只需使用&lt;object&gt;(如果有类型约束,则使用合适的类型)而不是&lt;&gt;

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

//returns true
type2.IsAssignableFrom(type1);

【讨论】:

  • 感谢您的回答。这是一种简单的检查方法。我可以理解type2.IsAssignableFrom(type1) 的行为。但是你的意思是两个开放的泛型类型在成为封闭类型或有界之前是独立的还是它们之间没有关系?
  • 您能具体说明您所说的“相关”是什么意思吗?当然,他们有某些关系,而不是其他关系。
  • 继承、实现等关系,但不包括继承和实现。但我不确定 open generic type 之间是否存在任何类型的关系。 @Jevgeni Geurtsen 认为特殊关系列表 AssignableFrom 存在。
  • 信不信由你,泛型类型定义没有任何实现。仅当您指定类型参数时才编译实现,并且仅针对该类型进行编译(尽管可以重复使用引用类型的实现,因为所有指针的大小都相同,但这只是实现细节)。所以你会问List&lt;&gt;是否实现IEnumerable&lt;&gt;没有多大意义,因为它一开始就没有实现。
  • @Jevgeni Geurtsen think the special relationship list AssignableFrom exist. 哦,但它肯定在框架代码中,所以关系存在,但只要它没有具体的实现,它就没有用,正如 John Wu 指出的那样。
【解决方案2】:

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

有什么方法可以检查两个open type之间的关系, 还是关系只存在于封闭类型上?

首先,关系永远存在;每个List&lt;&gt; 始终是IEnumerable&lt;&gt;,正如您在List&lt;T&gt; 类型的定义中看到的那样:

public class List&lt;T&gt; : IList&lt;T&gt;, ICollection&lt;T&gt;, IEnumerable&lt;T&gt;, ...

但这并不能回答您的第二个问题,如果有办法检查两种类型之间是否存在这种关系。你会认为IsAssignableFrom 方法可以用来检查类型 open 类型之间是否存在关系,但你不能。为什么?让我们在IsAssignableFromfunction的文档中找出答案:

Type.IsAssignableFrom (Type c) 如果以下任一条件为真,则返回真:

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

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

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

如果这些条件都不为真,或者 c 为空,则为假。

在您的情况下,上述条件都不会导致 true,因为:(1) 它们不是同一类型。 (2) 它们不能相互派生,因为它们是开放类型:它们的泛型类型参数是未知的 (unknown != unknown)。 List&lt;&gt; 实现封闭的 IEnumerable&lt;T&gt; 类型,而不是开放的 IEnumerable&lt;&gt; 类型 (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));

【讨论】:

    猜你喜欢
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多