【问题标题】:Determine if object is an instance of a generic base class, any generic type确定 object 是否是泛型基类的实例,任何泛型类型
【发布时间】:2016-05-12 10:24:49
【问题描述】:

我需要在不知道泛型类型参数的情况下测试一个值是否是泛型基类的实例。使用MSDN example 作为我示例的基础,这就是我想要完成的:

using System;

public class Class1<T> { }
public class DerivedC1 : Class1<int> { }

class IsSubclassTest
{
   public static void Main()
   {
      Console.WriteLine(
          "DerivedC1 subclass of Class1: {0}",
          typeof(DerivedC1).IsSubclassOf(typeof(Class1<>)) // <- Here.
      );
   }
}

虽然这在语法上是正确的,但它总是产生错误。如果我删除泛型类型参数,它会按预期工作(返回 true)。

如何在不知道其泛型类型参数的情况下测试类类型是否是泛型基类的子类?

【问题讨论】:

标签: c# reflection


【解决方案1】:

问题在于DrevidedC1不是Class1&lt;T&gt; 的子类,它是Class1&lt;int&gt; 的子类。确保您了解这种细微的差异; Class1&lt;T&gt; 是开放类型(T 可以是任何东西,它尚未设置)而 DerivedC1 扩展了封闭类型 Class1&lt;int&gt;(它不再在 T 中打开,T 设置为 @ 987654331@ 和仅int)。因此,当您执行以下操作时:

 typeof(DerivedC1).IsSubclassOf(typeof(Class1<>))

答案显然是false

您需要做的是检查DerivedC1 的基本类型的泛型类型定义(将其视为Class1&lt;int&gt; 的相应开放泛型类型)是否等于Class1&lt;T&gt;很明显。

因此正确的代码是:

typeof(DerivedC1).BaseType.GetGenericTypeDefinition() == typeof(Class1<>));

或者更好,正如 Matías Fidemraizer 在他的 answer 中所说:

typeof(DerivedC1).BaseType.GetGenericTypeDefinition().IsAssignableFrom(typeof(Class1<>)));

【讨论】:

  • @JohnWhite 除非您的检查可以使用反射和提供完整类型名称的类型来实现,否则由于您对检查进行强类型检查,因此检查来自不同程序集的类型应该没有问题。
【解决方案2】:

Type 有专门的方法来处理这类事情。据我所知,您需要遍历您的基本类型并依次检查每个类型,直到您(a)匹配或(b)到达继承层次结构的顶部(即System.Object) .

因此,以下(递归)扩展方法:

public static class TypeExtensions
{
    public static bool IsDerivedFromGenericParent(this Type type, Type parentType)
    {
        if(!parentType.IsGenericType)
        {
            throw new ArgumentException("type must be generic", "parentType");
        }
        if(type == null || type == typeof(object))
        {
            return false;
        }
        if(type.IsGenericType && type.GetGenericTypeDefinition() == parentType)
        {
            return true;
        }
        return type.BaseType.IsDerivedFromGenericParent(parentType)
            || type.GetInterfaces().Any(t=>t.IsDerivedFromGenericParent(parentType));
    }
}

将允许您执行以下操作

typeof(DerivedC1).IsDerivedFromGenericParent(typeof(Class1<>))

...如果您测试源自 DerivedC1 的内容,也可以使用。

【讨论】:

  • @JohnWhite 难道你正在测试一个接口实现?我调整了上面的代码以允许这样做。对于派生自List&lt;&gt; 的类似乎可以正常工作,并测试它是否是IEnumerable&lt;&gt;,这两者肯定都在不同的程序集中。
【解决方案3】:

在您的情况下,将 typeof(DerivedC1).IsSubclassOf(typeof(Class1&lt;&gt;)) 更改为 typeof(Class1&lt;&gt;).IsAssignableFrom(typeof(DerivedC1).BaseType.GetGenericTypeDefinition()) 就足够了。

Type.IsAssignableFrom 比使用Type.IsSubClassOf 更强大,因为它只是检查某个类型是否可分配给其他类型。这包括,同类型,接口类型等情况。

【讨论】:

  • “在你的情况下应该足够了”是什么意思?我正在努力让它发挥作用。当泛型类型参数是来自另一个程序集的类型时,它是否不够?
  • @JohnWhite 不,我的意思是,如果您在一个地方使用它,则不需要概括解决方案。您可以按原样使用 ;P
  • @JohnWhite 我会选择IsAssignableFrom 路由,它也可以检查接口类型。
  • 我确定我缺少一些东西。我复制了您提供的确切代码,在更改名称后运行正则表达式匹配以完全确保我做的一切正确,但它不会返回 true。我不知道发生了什么。显然,问题中的代码sn-p是minimal reproducible example
  • @JohnWhite Uhm,检查一下这个小提琴:dotnetfiddle.net/toLtnT 这里我为你提供了一个工作示例
猜你喜欢
  • 2011-08-23
  • 1970-01-01
  • 2011-06-11
  • 2011-03-20
  • 1970-01-01
  • 2019-01-20
  • 2022-12-16
  • 1970-01-01
  • 2011-04-15
相关资源
最近更新 更多