检查一个类是否从generics类派生
我有我的派生类项目中的generics类。
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的代码的答案是太棒了,但我有一个提示,如果您的genericstypes不是基于值types参数,它将不必要的。 我被挂在为什么“is”操作符不起作用,所以我也logging了我的实验结果以供将来参考。 请加强这个答案,以进一步提高其清晰度。
小费:
如果你确定你的GenericClass实现inheritance自GenericClassBase这样的抽象非generics基类,那么你可以问这个问题:
typeof(Test).IsSubclassOf(typeof(GenericClassBase))
IsSubclassOf()
我的testing表明,IsSubclassOf()不适用于无参数genericstypes,如
typeof(GenericClass<>)
而它将与之合作
typeof(GenericClass<SomeType>)
因此,下面的代码将适用于GenericClass <>的任何派生,假设您愿意基于SomeType进行testing:
typeof(Test).IsSubclassOf(typeof(GenericClass<SomeType>))
唯一可以想象的是,你想要通过GenericClass <>进行testing是在插件框架的情况下。
关于“是”运算符的思考
在devise时,C#不允许使用无参数的generics,因为在这一点上它们基本上不是一个完整的CLRtypes。 因此,必须用参数声明genericsvariables,这就是为什么“is”运算符对于处理对象非常强大的原因。 顺便说一句,“is”运算符也不能评估无参数的genericstypes。
“is”运算符将testing整个inheritance链,包括接口。
所以,给定任何对象的实例,下面的方法将做的伎俩:
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>); }
那么你会这样testing:
bool test1 = IsTypeofGenericClass<SomeType>(t);
我通过这些样本中的一些工作,发现他们在某些情况下是缺乏的。 该版本适用于各种generics:types,接口和types定义。
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; }
这里还有unit testing:
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); }
在我看来,这个实现在更多的情况下工作(通用的类和接口有或没有启动的参数,无论子和参数的数量):
public static class ReflexionExtension { public static bool IsSubClassOfGeneric(this Type child, Type parent) { if (child == parent) return false; if (child.IsSubclassOf(parent)) return true; var parameters = parent.GetGenericArguments(); var isParameterLessGeneric = !(parameters != null && parameters.Length > 0 && ((parameters[0].Attributes & TypeAttributes.BeforeFieldInit) == TypeAttributes.BeforeFieldInit)); while (child != null && child != typeof(object)) { var cur = GetFullTypeDefinition(child); if (parent == cur || (isParameterLessGeneric && cur.GetInterfaces().Select(i => GetFullTypeDefinition(i)).Contains(GetFullTypeDefinition(parent)))) return true; else if (!isParameterLessGeneric) if (GetFullTypeDefinition(parent) == cur && !cur.IsInterface) { if (VerifyGenericArguments(GetFullTypeDefinition(parent), cur)) if (VerifyGenericArguments(parent, child)) return true; } else foreach (var item in child.GetInterfaces().Where(i => GetFullTypeDefinition(parent) == GetFullTypeDefinition(i))) if (VerifyGenericArguments(parent, item)) return true; child = child.BaseType; } return false; } private static Type GetFullTypeDefinition(Type type) { return type.IsGenericType ? type.GetGenericTypeDefinition() : type; } private static bool VerifyGenericArguments(Type parent, Type child) { Type[] childArguments = child.GetGenericArguments(); Type[] parentArguments = parent.GetGenericArguments(); if (childArguments.Length == parentArguments.Length) for (int i = 0; i < childArguments.Length; i++) if (childArguments[i].Assembly != parentArguments[i].Assembly || childArguments[i].Name != parentArguments[i].Name || childArguments[i].Namespace != parentArguments[i].Namespace) if (!childArguments[i].IsSubclassOf(parentArguments[i])) return false; return true; } }
这里是我的70 76个testing用例:
[TestMethod] public void IsSubClassOfGenericTest() { Assert.IsTrue(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(BaseGeneric<>)), " 1"); Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(WrongBaseGeneric<>)), " 2"); Assert.IsTrue(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), " 3"); Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(IWrongBaseGeneric<>)), " 4"); Assert.IsTrue(typeof(IChildGeneric).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), " 5"); Assert.IsFalse(typeof(IWrongBaseGeneric<>).IsSubClassOfGeneric(typeof(ChildGeneric2<>)), " 6"); Assert.IsTrue(typeof(ChildGeneric2<>).IsSubClassOfGeneric(typeof(BaseGeneric<>)), " 7"); Assert.IsTrue(typeof(ChildGeneric2<Class1>).IsSubClassOfGeneric(typeof(BaseGeneric<>)), " 8"); Assert.IsTrue(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(BaseGeneric<Class1>)), " 9"); Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(WrongBaseGeneric<Class1>)), "10"); Assert.IsTrue(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "11"); Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(IWrongBaseGeneric<Class1>)), "12"); Assert.IsTrue(typeof(IChildGeneric).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "13"); Assert.IsFalse(typeof(BaseGeneric<Class1>).IsSubClassOfGeneric(typeof(ChildGeneric2<Class1>)), "14"); Assert.IsTrue(typeof(ChildGeneric2<Class1>).IsSubClassOfGeneric(typeof(BaseGeneric<Class1>)), "15"); Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(ChildGeneric)), "16"); Assert.IsFalse(typeof(IChildGeneric).IsSubClassOfGeneric(typeof(IChildGeneric)), "17"); Assert.IsFalse(typeof(IBaseGeneric<>).IsSubClassOfGeneric(typeof(IChildGeneric2<>)), "18"); Assert.IsTrue(typeof(IChildGeneric2<>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "19"); Assert.IsTrue(typeof(IChildGeneric2<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "20"); Assert.IsFalse(typeof(IBaseGeneric<Class1>).IsSubClassOfGeneric(typeof(IChildGeneric2<Class1>)), "21"); Assert.IsTrue(typeof(IChildGeneric2<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "22"); Assert.IsFalse(typeof(IBaseGeneric<Class1>).IsSubClassOfGeneric(typeof(BaseGeneric<Class1>)), "23"); Assert.IsTrue(typeof(BaseGeneric<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "24"); Assert.IsFalse(typeof(IBaseGeneric<>).IsSubClassOfGeneric(typeof(BaseGeneric<>)), "25"); Assert.IsTrue(typeof(BaseGeneric<>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "26"); Assert.IsTrue(typeof(BaseGeneric<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "27"); Assert.IsFalse(typeof(IBaseGeneric<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "28"); Assert.IsTrue(typeof(BaseGeneric2<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "29"); Assert.IsFalse(typeof(IBaseGeneric<>).IsSubClassOfGeneric(typeof(BaseGeneric2<>)), "30"); Assert.IsTrue(typeof(BaseGeneric2<>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "31"); Assert.IsTrue(typeof(BaseGeneric2<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "32"); Assert.IsTrue(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(BaseGenericA<,>)), "33"); Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(WrongBaseGenericA<,>)), "34"); Assert.IsTrue(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "35"); Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(IWrongBaseGenericA<,>)), "36"); Assert.IsTrue(typeof(IChildGenericA).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "37"); Assert.IsFalse(typeof(IWrongBaseGenericA<,>).IsSubClassOfGeneric(typeof(ChildGenericA2<,>)), "38"); Assert.IsTrue(typeof(ChildGenericA2<,>).IsSubClassOfGeneric(typeof(BaseGenericA<,>)), "39"); Assert.IsTrue(typeof(ChildGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(BaseGenericA<,>)), "40"); Assert.IsTrue(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(BaseGenericA<ClassA, ClassB>)), "41"); Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(WrongBaseGenericA<ClassA, ClassB>)), "42"); Assert.IsTrue(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "43"); Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(IWrongBaseGenericA<ClassA, ClassB>)), "44"); Assert.IsTrue(typeof(IChildGenericA).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "45"); Assert.IsFalse(typeof(BaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(ChildGenericA2<ClassA, ClassB>)), "46"); Assert.IsTrue(typeof(ChildGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(BaseGenericA<ClassA, ClassB>)), "47"); Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(ChildGenericA)), "48"); Assert.IsFalse(typeof(IChildGenericA).IsSubClassOfGeneric(typeof(IChildGenericA)), "49"); Assert.IsFalse(typeof(IBaseGenericA<,>).IsSubClassOfGeneric(typeof(IChildGenericA2<,>)), "50"); Assert.IsTrue(typeof(IChildGenericA2<,>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "51"); Assert.IsTrue(typeof(IChildGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "52"); Assert.IsFalse(typeof(IBaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IChildGenericA2<ClassA, ClassB>)), "53"); Assert.IsTrue(typeof(IChildGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "54"); Assert.IsFalse(typeof(IBaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(BaseGenericA<ClassA, ClassB>)), "55"); Assert.IsTrue(typeof(BaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "56"); Assert.IsFalse(typeof(IBaseGenericA<,>).IsSubClassOfGeneric(typeof(BaseGenericA<,>)), "57"); Assert.IsTrue(typeof(BaseGenericA<,>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "58"); Assert.IsTrue(typeof(BaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "59"); Assert.IsFalse(typeof(IBaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "60"); Assert.IsTrue(typeof(BaseGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "61"); Assert.IsFalse(typeof(IBaseGenericA<,>).IsSubClassOfGeneric(typeof(BaseGenericA2<,>)), "62"); Assert.IsTrue(typeof(BaseGenericA2<,>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "63"); Assert.IsTrue(typeof(BaseGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "64"); Assert.IsFalse(typeof(BaseGenericA2<ClassB, ClassA>).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "65"); Assert.IsFalse(typeof(BaseGenericA<ClassB, ClassA>).IsSubClassOfGeneric(typeof(ChildGenericA2<ClassA, ClassB>)), "66"); Assert.IsFalse(typeof(BaseGenericA2<ClassB, ClassA>).IsSubClassOfGeneric(typeof(BaseGenericA<ClassA, ClassB>)), "67"); Assert.IsTrue(typeof(ChildGenericA3<ClassA, ClassB>).IsSubClassOfGeneric(typeof(BaseGenericB<ClassA, ClassB, ClassC>)), "68"); Assert.IsTrue(typeof(ChildGenericA4<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericB<ClassA, ClassB, ClassC>)), "69"); Assert.IsFalse(typeof(ChildGenericA3<ClassB, ClassA>).IsSubClassOfGeneric(typeof(BaseGenericB<ClassA, ClassB, ClassC>)), "68-2"); Assert.IsTrue(typeof(ChildGenericA3<ClassA, ClassB2>).IsSubClassOfGeneric(typeof(BaseGenericB<ClassA, ClassB, ClassC>)), "68-3"); Assert.IsFalse(typeof(ChildGenericA3<ClassB2, ClassA>).IsSubClassOfGeneric(typeof(BaseGenericB<ClassA, ClassB, ClassC>)), "68-4"); Assert.IsFalse(typeof(ChildGenericA4<ClassB, ClassA>).IsSubClassOfGeneric(typeof(IBaseGenericB<ClassA, ClassB, ClassC>)), "69-2"); Assert.IsTrue(typeof(ChildGenericA4<ClassA, ClassB2>).IsSubClassOfGeneric(typeof(IBaseGenericB<ClassA, ClassB, ClassC>)), "69-3"); Assert.IsFalse(typeof(ChildGenericA4<ClassB2, ClassA>).IsSubClassOfGeneric(typeof(IBaseGenericB<ClassA, ClassB, ClassC>)), "69-4"); Assert.IsFalse(typeof(bool).IsSubClassOfGeneric(typeof(IBaseGenericB<ClassA, ClassB, ClassC>)), "70"); }
testing的类和接口:
public class Class1 { } public class BaseGeneric<T> : IBaseGeneric<T> { } public class BaseGeneric2<T> : IBaseGeneric<T>, IInterfaceBidon { } public interface IBaseGeneric<T> { } public class ChildGeneric : BaseGeneric<Class1> { } public interface IChildGeneric : IBaseGeneric<Class1> { } public class ChildGeneric2<Class1> : BaseGeneric<Class1> { } public interface IChildGeneric2<Class1> : IBaseGeneric<Class1> { } public class WrongBaseGeneric<T> { } public interface IWrongBaseGeneric<T> { } public interface IInterfaceBidon { } public class ClassA { } public class ClassB { } public class ClassC { } public class ClassB2 : ClassB { } public class BaseGenericA<T, U> : IBaseGenericA<T, U> { } public class BaseGenericB<T, U, V> { } public interface IBaseGenericB<ClassA, ClassB, ClassC> { } public class BaseGenericA2<T, U> : IBaseGenericA<T, U>, IInterfaceBidonA { } public interface IBaseGenericA<T, U> { } public class ChildGenericA : BaseGenericA<ClassA, ClassB> { } public interface IChildGenericA : IBaseGenericA<ClassA, ClassB> { } public class ChildGenericA2<ClassA, ClassB> : BaseGenericA<ClassA, ClassB> { } public class ChildGenericA3<ClassA, ClassB> : BaseGenericB<ClassA, ClassB, ClassC> { } public class ChildGenericA4<ClassA, ClassB> : IBaseGenericB<ClassA, ClassB, ClassC> { } public interface IChildGenericA2<ClassA, ClassB> : IBaseGenericA<ClassA, ClassB> { } public class WrongBaseGenericA<T, U> { } public interface IWrongBaseGenericA<T, U> { } public interface IInterfaceBidonA { }
这是我创build的一个小方法,用于检查对象是否从特定types派生。 对我很好!
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); }
JaredPar的代码工作,但只为一个级别的inheritance。 对于无限级别的inheritance,请使用以下代码
public bool IsTypeDerivedFromGenericType(Type typeToCheck, Type genericType) { if (typeToCheck == typeof(object)) { return false; } else if (typeToCheck == null) { return false; } else if (typeToCheck.IsGenericType && typeToCheck.GetGenericTypeDefinition() == genericType) { return true; } else { return IsTypeDerivedFromGenericType(typeToCheck.BaseType, genericType); } }
这可能是矫枉过正,但我使用如下扩展方法。 他们检查接口以及子类。 它也可以返回具有指定generics定义的types。
例如,对于问题中的示例,可以针对通用接口以及generics类进行testing。 返回的types可以与GetGenericArguments
一起使用,以确定generics参数types是“SomeType”。
/// <summary> /// Checks whether this type has the specified definition in its ancestry. /// </summary> public static bool HasGenericDefinition(this Type type, Type definition) { return GetTypeWithGenericDefinition(type, definition) != null; } /// <summary> /// Returns the actual type implementing the specified definition from the /// ancestry of the type, if available. Else, null. /// </summary> public static Type GetTypeWithGenericDefinition(this Type type, Type definition) { if (type == null) throw new ArgumentNullException("type"); if (definition == null) throw new ArgumentNullException("definition"); if (!definition.IsGenericTypeDefinition) throw new ArgumentException( "The definition needs to be a GenericTypeDefinition", "definition"); if (definition.IsInterface) foreach (var interfaceType in type.GetInterfaces()) if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == definition) return interfaceType; for (Type t = type; t != null; t = t.BaseType) if (t.IsGenericType && t.GetGenericTypeDefinition() == definition) return t; return null; }
基于上面fir3rpho3nixx和David Schmitt的优秀答案,我修改了他们的代码并添加了ShouldInheritOrImplementTypedGenericInterfacetesting(最后一个)。
/// <summary> /// Find out if a child type implements or inherits from the parent type. /// The parent type can be an interface or a concrete class, generic or non-generic. /// </summary> /// <param name="child"></param> /// <param name="parent"></param> /// <returns></returns> public static bool InheritsOrImplements(this Type child, Type parent) { var currentChild = parent.IsGenericTypeDefinition && child.IsGenericType ? child.GetGenericTypeDefinition() : child; while (currentChild != typeof(object)) { if (parent == currentChild || HasAnyInterfaces(parent, currentChild)) return true; currentChild = currentChild.BaseType != null && parent.IsGenericTypeDefinition && 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 = parent.IsGenericTypeDefinition && childInterface.IsGenericType ? childInterface.GetGenericTypeDefinition() : childInterface; return currentInterface == parent; }); } [Test] public void ShouldInheritOrImplementNonGenericInterface() { Assert.That(typeof(FooImplementor) .InheritsOrImplements(typeof(IFooInterface)), Is.True); } [Test] public void ShouldInheritOrImplementGenericInterface() { Assert.That(typeof(GenericFooBase) .InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True); } [Test] public void ShouldInheritOrImplementGenericInterfaceByGenericSubclass() { Assert.That(typeof(GenericFooImplementor<>) .InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True); } [Test] public void ShouldInheritOrImplementGenericInterfaceByGenericSubclassNotCaringAboutGenericTypeParameter() { Assert.That(new GenericFooImplementor<string>().GetType() .InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True); } [Test] public void ShouldNotInheritOrImplementGenericInterfaceByGenericSubclassNotCaringAboutGenericTypeParameter() { Assert.That(new GenericFooImplementor<string>().GetType() .InheritsOrImplements(typeof(IGenericFooInterface<int>)), Is.False); } [Test] public void ShouldInheritOrImplementNonGenericClass() { Assert.That(typeof(FooImplementor) .InheritsOrImplements(typeof(FooBase)), Is.True); } [Test] public void ShouldInheritOrImplementAnyBaseType() { Assert.That(typeof(GenericFooImplementor<>) .InheritsOrImplements(typeof(FooBase)), Is.True); } [Test] public void ShouldInheritOrImplementTypedGenericInterface() { GenericFooImplementor<int> obj = new GenericFooImplementor<int>(); Type t = obj.GetType(); Assert.IsTrue(t.InheritsOrImplements(typeof(IGenericFooInterface<int>))); Assert.IsFalse(t.InheritsOrImplements(typeof(IGenericFooInterface<String>))); }
这一切都可以用linq轻松完成。 这将find任何types的generics基类GenericBaseType的子类。
IEnumerable<Type> allTypes = Assembly.GetExecutingAssembly().GetTypes(); IEnumerable<Type> mySubclasses = allTypes.Where(t => t.BaseType != null && t.BaseType.IsGenericType && t.BaseType.GetGenericTypeDefinition() == typeof(GenericBaseType<,>));
简单的解决scheme:只需创build并添加第二个非generics接口到generics类:
public interface IGenericClass { } public class GenericClass<T> : GenericInterface<T>, IGenericClass { }
那么就用你喜欢的方式来检查, as
IsAssignableFrom
等。
if (thing is IGenericClass) { // Do work {
显然,只有在编辑generics类(OP似乎具有)的能力的情况下才有可能,但比使用隐秘扩展方法更加优雅和可读。
添加到@ jaredpar的答案,这是我用来检查接口:
public static bool IsImplementerOfRawGeneric(this Type type, Type toCheck) { if(type.IsClass) { return false; } return toCheck.GetInterfaces().Any(interfaceType => { var current = interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType; return current == type; }); } public static bool IsSubTypeOfRawGeneric(this Type type, Type toCheck) { return type.IsInterface ? IsImplementerOfRawGeneric(type, toCheck) : IsSubclassOfRawGeneric(type, toCheck); }
例如:
Console.WriteLine(typeof(IList<>).IsSubTypeOfRawGeneric(typeof(IList<int>))); // true
JaredPar,
如果我传入typeof(types<>)作为toCheck,这对我不起作用。 这是我改变的。
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; }
Type _type = myclass.GetType(); PropertyInfo[] _propertyInfos = _type.GetProperties(); Boolean _test = _propertyInfos[0].PropertyType.GetGenericTypeDefinition() == typeof(List<>);
你可以试试这个扩展
public static bool IsSubClassOfGenericClass(this Type type, Type genericClass,Type t) { return type.IsSubclassOf(genericClass.MakeGenericType(new[] { t })); }
在这个游戏迟到…我也有另一个JarodPar的答案排列。
这里是Type.IsSubClassOf(types)礼貌reflection器:
public virtual bool IsSubclassOf(Type c) { Type baseType = this; if (!(baseType == c)) { while (baseType != null) { if (baseType == c) { return true; } baseType = baseType.BaseType; } return false; } return false; }
从这个angular度来看,我们发现它没有做任何事情,而且与JaredPar的迭代方法类似。 到现在为止还挺好。 这是我的版本(免责声明:没有经过彻底testing,所以我知道你是否发现问题)
public static bool IsExtension(this Type thisType, Type potentialSuperType) { // // protect ya neck // if (thisType == null || potentialSuperType == null || thisType == potentialSuperType) return false; // // don't need to traverse inheritance for interface extension, so check/do these first // if (potentialSuperType.IsInterface) { foreach (var interfaceType in thisType.GetInterfaces()) { var tempType = interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType; if (tempType == potentialSuperType) { return true; } } } // // do the concrete type checks, iterating up the inheritance chain, as in orignal // while (thisType != null && thisType != typeof(object)) { var cur = thisType.IsGenericType ? thisType.GetGenericTypeDefinition() : thisType; if (potentialSuperType == cur) { return true; } thisType = thisType.BaseType; } return false; }
basically this is just an extension method to System.Type – i did this to intentionally limit the "thisType" Type to concrete Types, as my immediate usage is to LINQ query "where" predicates against Type objects. i'm sure all you smart folks out there could bang it down to an efficient, all-purpose static method if you need to 🙂 the code does a few things the answer's code doesn't
- open's it up to to general "extension" – i'm considering inheritance (think classes) as well as implementation (interfaces); method and parameter names are changed to better reflect this
- input null-validation (meah)
- input of same type (a class cannot extend itself)
- short-circuit execution if Type in question is an interface; because GetInterfaces() returns all implemented interfaces (even ones implemented in super-classes), you can simply loop through that collection not having to climb the inheritance tree
the rest is basically the same as JaredPar's code