我有一个泛型类在我的项目与派生类。
public class GenericClass<T> : GenericInterface<T>
{
}
public class Test : GenericClass<SomeType>
{
}
是否有任何方法可以查明Type对象是否派生自GenericClass?
t.IsSubclassOf(typeof(GenericClass<>))
不管用。
我有一个泛型类在我的项目与派生类。
public class GenericClass<T> : GenericInterface<T>
{
}
public class Test : GenericClass<SomeType>
{
}
是否有任何方法可以查明Type对象是否派生自GenericClass?
t.IsSubclassOf(typeof(GenericClass<>))
不管用。
当前回答
Type _type = myclass.GetType();
PropertyInfo[] _propertyInfos = _type.GetProperties();
Boolean _test = _propertyInfos[0].PropertyType.GetGenericTypeDefinition()
== typeof(List<>);
其他回答
(由于大量重写而重新发布)
JaredPar的代码回答非常棒,但是我有一个技巧,如果您的泛型类型不是基于值类型参数,那么就没有必要这样做。我一直纠结于为什么“is”操作符不能工作,所以我还记录了我的实验结果,以供将来参考。请加强这个答案,以进一步提高其清晰度。
TIP:
如果你确定你的GenericClass实现继承自一个抽象的非泛型基类,比如GenericClassBase,你可以毫不费力地问同样的问题,就像这样:
typeof(Test).IsSubclassOf(typeof(GenericClassBase))
IsSubclassOf()
我的测试表明IsSubclassOf()不适用于无参数的泛型类型,例如
typeof(GenericClass<>)
而它将与
typeof(GenericClass<SomeType>)
因此,以下代码将适用于GenericClass<>的任何派生,假设您愿意基于SomeType进行测试:
typeof(Test).IsSubclassOf(typeof(GenericClass<SomeType>))
我能想象到您希望通过GenericClass<>进行测试的唯一情况是在插件框架场景中。
对“is”操作符的思考
在设计时,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);
}
添加到@jaredpar的答案中,下面是我用来检查接口的方法:
public static bool IsImplementerOfRawGeneric(this Type type, Type toCheck)
{
if (toCheck.GetTypeInfo().IsClass)
{
return false;
}
return type.GetInterfaces().Any(interfaceType =>
{
var current = interfaceType.GetTypeInfo().IsGenericType ?
interfaceType.GetGenericTypeDefinition() : interfaceType;
return current == toCheck;
});
}
public static bool IsSubTypeOfRawGeneric(this Type type, Type toCheck)
{
return type.IsInterface ?
IsImplementerOfRawGeneric(type, toCheck)
: IsSubclassOfRawGeneric(type, toCheck);
}
Ex:
Console.WriteLine(typeof(IList<>).IsSubTypeOfRawGeneric(typeof(IList<int>))); // true
贾里德帕尔
这并不为我工作,如果我通过typeof(type<>)作为检查。这是我改变的地方。
static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) {
while (toCheck != typeof(object)) {
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (cur.IsGenericType && generic.GetGenericTypeDefinition() == cur.GetGenericTypeDefinition()) {
return true;
}
toCheck = toCheck.BaseType;
}
return false;
}
下面是我创建的一个小方法,用于检查对象是否派生于特定类型。对我来说太棒了!
internal static bool IsDerivativeOf(this Type t, Type typeToCompare)
{
if (t == null) throw new NullReferenceException();
if (t.BaseType == null) return false;
if (t.BaseType == typeToCompare) return true;
else return t.BaseType.IsDerivativeOf(typeToCompare);
}