我需要测试一个值是否是泛型基类的实例,而不知道泛型类型参数。使用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)。
如何在不知道其泛型类型参数的情况下测试类类型是否为泛型基类的子类?
答案 0 :(得分:5)
问题是DrevidedC1
不是Class1<T>
的次级,它是Class1<int>
的子类。确保你理解这种微妙的差异; Class1<T>
是一种开放式广告(T
可以是任何内容,但尚未设置),而DerivedC1
扩展了已关闭的类型Class1<int>
(它未在{{1}中打开} {},T
设置为T
且仅int
)。因此,当您执行以下操作时:
int
答案显然是 typeof(DerivedC1).IsSubclassOf(typeof(Class1<>))
。
您需要做的是检查false
的基类型的泛型类型定义(将其视为DerivedC1
的相应开放泛型类型)等于它显然是Class1<int>
。
因此,正确的代码是:
Class1<T>
或者更好,正如MatíasFidemraizer在他的answer中所述:
typeof(DerivedC1).BaseType.GetGenericTypeDefinition() == typeof(Class1<>));
答案 1 :(得分:4)
Type
对此类事情有特殊方法。据我所知,你需要走基础类型并依次检查每个类型,直到你(a)匹配或(b)到达继承层次结构的顶部(即{{1} })。
因此,以下(递归)扩展方法:
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<>))
派生的内容,也会有效。
答案 2 :(得分:2)
将typeof(DerivedC1).IsSubclassOf(typeof(Class1<>))
更改为typeof(Class1<>).IsAssignableFrom(typeof(DerivedC1).BaseType.GetGenericTypeDefinition())
就足够了。
Type.IsAssignableFrom
比使用Type.IsSubClassOf
更强大,因为它只检查某些类型是否可以分配给其他类型。这包括相同类型,接口类型和其他情况。