检查一个类是否从泛型类派生
我在派生类的项目中有一个泛型类。
public class GenericClass<T> : GenericInterface<T>
{
}
public class Test : GenericClass<SomeType>
{
}
有没有什么方法可以找出Type
对象是否是从GenericClass
派生的?
t.IsSubclassOf(typeof(GenericClass<>))
不起作用。
试试这个代码
static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) {
while (toCheck != null && toCheck != typeof(object)) {
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (generic == cur) {
return true;
}
toCheck = toCheck.BaseType;
}
return false;
}
(由于大量改写而重新发布)
JaredPar的代码答案很棒,但是我有一个提示,如果你的泛型类型不是基于值类型参数的话,那么它就不必要了。 我被挂上了为什么“是”运营商无法工作,所以我也记录了我的实验结果以供将来参考。 请增强此答案以进一步提高其清晰度。
小费:
如果你确定你的GenericClass实现继承自GenericClassBase这样的抽象非泛型基类,那么你可以问这样一个问题:
typeof(Test).IsSubclassOf(typeof(GenericClassBase))
IsSubclassOf()
我的测试表明IsSubclassOf()不适用于无参数泛型类型,如
typeof(GenericClass<>)
而它将与之合作
typeof(GenericClass<SomeType>)
因此,下面的代码将适用于GenericClass <>的任何派生,假设您愿意基于SomeType进行测试:
typeof(Test).IsSubclassOf(typeof(GenericClass<SomeType>))
唯一我能想象的是,你想要通过GenericClass <>进行测试是在插件框架的情况下。
关于“是”运算符的思考
在设计时,C#不允许使用无参数泛型,因为它们在本质上并不是完整的CLR类型。 因此,必须用参数声明通用变量,这就是为什么“is”运算符对于处理对象非常强大的原因。 顺便说一下,“is”运算符也不能评估无参数的泛型类型。
“is”运算符将测试整个继承链,包括接口。
因此,给定一个任何对象的实例,下面的方法将做到这一点:
bool IsTypeof<T>(object t)
{
return (t is T);
}
这有点多余,但我想我会继续为每个人想象它。
特定
var t = new Test();
以下几行代码将返回true:
bool test1 = IsTypeof<GenericInterface<SomeType>>(t);
bool test2 = IsTypeof<GenericClass<SomeType>>(t);
bool test3 = IsTypeof<Test>(t);
另一方面,如果你想要特定于GenericClass的东西,你可以使它更具体,我想是这样的:
bool IsTypeofGenericClass<SomeType>(object t)
{
return (t is GenericClass<SomeType>);
}
然后你会这样测试:
bool test1 = IsTypeofGenericClass<SomeType>(t);
我通过其中一些样本进行了工作,发现在某些情况下缺乏这些样本。 该版本适用于各种泛型:类型,接口和类型定义。
public static bool InheritsOrImplements(this Type child, Type parent)
{
parent = ResolveGenericTypeDefinition(parent);
var currentChild = child.IsGenericType
? child.GetGenericTypeDefinition()
: child;
while (currentChild != typeof (object))
{
if (parent == currentChild || HasAnyInterfaces(parent, currentChild))
return true;
currentChild = currentChild.BaseType != null
&& currentChild.BaseType.IsGenericType
? currentChild.BaseType.GetGenericTypeDefinition()
: currentChild.BaseType;
if (currentChild == null)
return false;
}
return false;
}
private static bool HasAnyInterfaces(Type parent, Type child)
{
return child.GetInterfaces()
.Any(childInterface =>
{
var currentInterface = childInterface.IsGenericType
? childInterface.GetGenericTypeDefinition()
: childInterface;
return currentInterface == parent;
});
}
private static Type ResolveGenericTypeDefinition(Type parent)
{
var shouldUseGenericType = true;
if (parent.IsGenericType && parent.GetGenericTypeDefinition() != parent)
shouldUseGenericType = false;
if (parent.IsGenericType && shouldUseGenericType)
parent = parent.GetGenericTypeDefinition();
return parent;
}
这里还有单元测试:
protected interface IFooInterface
{
}
protected interface IGenericFooInterface<T>
{
}
protected class FooBase
{
}
protected class FooImplementor
: FooBase, IFooInterface
{
}
protected class GenericFooBase
: FooImplementor, IGenericFooInterface<object>
{
}
protected class GenericFooImplementor<T>
: FooImplementor, IGenericFooInterface<T>
{
}
[Test]
public void Should_inherit_or_implement_non_generic_interface()
{
Assert.That(typeof(FooImplementor)
.InheritsOrImplements(typeof(IFooInterface)), Is.True);
}
[Test]
public void Should_inherit_or_implement_generic_interface()
{
Assert.That(typeof(GenericFooBase)
.InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
}
[Test]
public void Should_inherit_or_implement_generic_interface_by_generic_subclass()
{
Assert.That(typeof(GenericFooImplementor<>)
.InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
}
[Test]
public void Should_inherit_or_implement_generic_interface_by_generic_subclass_not_caring_about_generic_type_parameter()
{
Assert.That(new GenericFooImplementor<string>().GetType()
.InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
}
[Test]
public void Should_not_inherit_or_implement_generic_interface_by_generic_subclass_not_caring_about_generic_type_parameter()
{
Assert.That(new GenericFooImplementor<string>().GetType()
.InheritsOrImplements(typeof(IGenericFooInterface<int>)), Is.False);
}
[Test]
public void Should_inherit_or_implement_non_generic_class()
{
Assert.That(typeof(FooImplementor)
.InheritsOrImplements(typeof(FooBase)), Is.True);
}
[Test]
public void Should_inherit_or_implement_any_base_type()
{
Assert.That(typeof(GenericFooImplementor<>)
.InheritsOrImplements(typeof(FooBase)), Is.True);
}
链接地址: http://www.djcxy.com/p/76503.html