我的项目中有一个派生类的泛型类.
public class GenericClass: GenericInterface { } public class Test : GenericClass { }
有没有办法找出一个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()不适用于无参数泛型类型,例如
typeof(GenericClass<>)
而它会合作
typeof(GenericClass)
因此,以下代码适用于GenericClass <>的任何派生,假设您愿意基于SomeType进行测试:
typeof(Test).IsSubclassOf(typeof(GenericClass))
我唯一想象你想要通过GenericClass <>进行测试的是插件框架场景.
在设计时,C#不允许使用无参数泛型,因为它们在那时基本上不是完整的CLR类型.因此,您必须使用参数声明泛型变量,这就是"is"运算符对于处理对象非常强大的原因.顺便说一句,"是"运算符也不能评估无参数的泛型类型.
"is"运算符将测试整个继承链,包括接口.
因此,给定任何对象的实例,以下方法将起到作用:
bool IsTypeof(object t) { return (t is T); }
这有点多余,但我想我会继续为每个人想象它.
特定
var t = new Test();
以下代码行将返回true:
bool test1 = IsTypeof>(t); bool test2 = IsTypeof >(t); bool test3 = IsTypeof (t);
另一方面,如果你想要特定于GenericClass的东西,你可以使它更具体,我想,像这样:
bool IsTypeofGenericClass(object t) { return (t is GenericClass ); }
然后你会像这样测试:
bool test1 = IsTypeofGenericClass(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{ } protected class FooBase { } protected class FooImplementor : FooBase, IFooInterface { } protected class GenericFooBase : FooImplementor, IGenericFooInterface
在我看来,这个实现在更多情况下工作(泛型类和接口有或没有启动参数,无论子和参数的数量):
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个测试用例:
[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).IsSubClassOfGeneric(typeof(BaseGeneric<>)), " 8"); Assert.IsTrue(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(BaseGeneric )), " 9"); Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(WrongBaseGeneric )), "10"); Assert.IsTrue(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(IBaseGeneric )), "11"); Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(IWrongBaseGeneric )), "12"); Assert.IsTrue(typeof(IChildGeneric).IsSubClassOfGeneric(typeof(IBaseGeneric )), "13"); Assert.IsFalse(typeof(BaseGeneric ).IsSubClassOfGeneric(typeof(ChildGeneric2 )), "14"); Assert.IsTrue(typeof(ChildGeneric2 ).IsSubClassOfGeneric(typeof(BaseGeneric )), "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 ).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "20"); Assert.IsFalse(typeof(IBaseGeneric ).IsSubClassOfGeneric(typeof(IChildGeneric2 )), "21"); Assert.IsTrue(typeof(IChildGeneric2 ).IsSubClassOfGeneric(typeof(IBaseGeneric )), "22"); Assert.IsFalse(typeof(IBaseGeneric ).IsSubClassOfGeneric(typeof(BaseGeneric )), "23"); Assert.IsTrue(typeof(BaseGeneric ).IsSubClassOfGeneric(typeof(IBaseGeneric )), "24"); Assert.IsFalse(typeof(IBaseGeneric<>).IsSubClassOfGeneric(typeof(BaseGeneric<>)), "25"); Assert.IsTrue(typeof(BaseGeneric<>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "26"); Assert.IsTrue(typeof(BaseGeneric ).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "27"); Assert.IsFalse(typeof(IBaseGeneric ).IsSubClassOfGeneric(typeof(IBaseGeneric )), "28"); Assert.IsTrue(typeof(BaseGeneric2 ).IsSubClassOfGeneric(typeof(IBaseGeneric )), "29"); Assert.IsFalse(typeof(IBaseGeneric<>).IsSubClassOfGeneric(typeof(BaseGeneric2<>)), "30"); Assert.IsTrue(typeof(BaseGeneric2<>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "31"); Assert.IsTrue(typeof(BaseGeneric2 ).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 ).IsSubClassOfGeneric(typeof(BaseGenericA<,>)), "40"); Assert.IsTrue(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(BaseGenericA )), "41"); Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(WrongBaseGenericA )), "42"); Assert.IsTrue(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(IBaseGenericA )), "43"); Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(IWrongBaseGenericA )), "44"); Assert.IsTrue(typeof(IChildGenericA).IsSubClassOfGeneric(typeof(IBaseGenericA )), "45"); Assert.IsFalse(typeof(BaseGenericA ).IsSubClassOfGeneric(typeof(ChildGenericA2 )), "46"); Assert.IsTrue(typeof(ChildGenericA2 ).IsSubClassOfGeneric(typeof(BaseGenericA )), "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 ).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "52"); Assert.IsFalse(typeof(IBaseGenericA ).IsSubClassOfGeneric(typeof(IChildGenericA2 )), "53"); Assert.IsTrue(typeof(IChildGenericA2 ).IsSubClassOfGeneric(typeof(IBaseGenericA )), "54"); Assert.IsFalse(typeof(IBaseGenericA ).IsSubClassOfGeneric(typeof(BaseGenericA )), "55"); Assert.IsTrue(typeof(BaseGenericA ).IsSubClassOfGeneric(typeof(IBaseGenericA )), "56"); Assert.IsFalse(typeof(IBaseGenericA<,>).IsSubClassOfGeneric(typeof(BaseGenericA<,>)), "57"); Assert.IsTrue(typeof(BaseGenericA<,>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "58"); Assert.IsTrue(typeof(BaseGenericA ).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "59"); Assert.IsFalse(typeof(IBaseGenericA ).IsSubClassOfGeneric(typeof(IBaseGenericA )), "60"); Assert.IsTrue(typeof(BaseGenericA2 ).IsSubClassOfGeneric(typeof(IBaseGenericA )), "61"); Assert.IsFalse(typeof(IBaseGenericA<,>).IsSubClassOfGeneric(typeof(BaseGenericA2<,>)), "62"); Assert.IsTrue(typeof(BaseGenericA2<,>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "63"); Assert.IsTrue(typeof(BaseGenericA2 ).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "64"); Assert.IsFalse(typeof(BaseGenericA2 ).IsSubClassOfGeneric(typeof(IBaseGenericA )), "65"); Assert.IsFalse(typeof(BaseGenericA ).IsSubClassOfGeneric(typeof(ChildGenericA2 )), "66"); Assert.IsFalse(typeof(BaseGenericA2 ).IsSubClassOfGeneric(typeof(BaseGenericA )), "67"); Assert.IsTrue(typeof(ChildGenericA3 ).IsSubClassOfGeneric(typeof(BaseGenericB )), "68"); Assert.IsTrue(typeof(ChildGenericA4 ).IsSubClassOfGeneric(typeof(IBaseGenericB )), "69"); Assert.IsFalse(typeof(ChildGenericA3 ).IsSubClassOfGeneric(typeof(BaseGenericB )), "68-2"); Assert.IsTrue(typeof(ChildGenericA3 ).IsSubClassOfGeneric(typeof(BaseGenericB )), "68-3"); Assert.IsFalse(typeof(ChildGenericA3 ).IsSubClassOfGeneric(typeof(BaseGenericB )), "68-4"); Assert.IsFalse(typeof(ChildGenericA4 ).IsSubClassOfGeneric(typeof(IBaseGenericB )), "69-2"); Assert.IsTrue(typeof(ChildGenericA4 ).IsSubClassOfGeneric(typeof(IBaseGenericB )), "69-3"); Assert.IsFalse(typeof(ChildGenericA4 ).IsSubClassOfGeneric(typeof(IBaseGenericB )), "69-4"); Assert.IsFalse(typeof(bool).IsSubClassOfGeneric(typeof(IBaseGenericB )), "70"); }
用于测试的类和接口:
public class Class1 { } public class BaseGeneric: IBaseGeneric { } public class BaseGeneric2 : IBaseGeneric , IInterfaceBidon { } public interface IBaseGeneric { } public class ChildGeneric : BaseGeneric { } public interface IChildGeneric : IBaseGeneric { } public class ChildGeneric2 : BaseGeneric { } public interface IChildGeneric2 : IBaseGeneric { } public class WrongBaseGeneric { } public interface IWrongBaseGeneric { } public interface IInterfaceBidon { } public class ClassA { } public class ClassB { } public class ClassC { } public class ClassB2 : ClassB { } public class BaseGenericA : IBaseGenericA { } public class BaseGenericB { } public interface IBaseGenericB { } public class BaseGenericA2 : IBaseGenericA , IInterfaceBidonA { } public interface IBaseGenericA { } public class ChildGenericA : BaseGenericA { } public interface IChildGenericA : IBaseGenericA { } public class ChildGenericA2 : BaseGenericA { } public class ChildGenericA3 : BaseGenericB { } public class ChildGenericA4 : IBaseGenericB { } public interface IChildGenericA2 : IBaseGenericA { } public class WrongBaseGenericA { } public interface IWrongBaseGenericA { } public interface IInterfaceBidonA { }
JaredPar的代码可以工作,但只适用于一个级别的继承.对于无限级别的继承,请使用以下代码
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); } }
这是我创建的一个用于检查对象是否来自特定类型的方法.对我来说很棒!
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); }
它可能有点矫枉过正,但我使用如下的扩展方法.他们检查接口和子类.它还可以返回具有指定泛型定义的类型.
例如,对于问题中的示例,它可以针对通用接口以及泛型类进行测试.返回的类型可用于GetGenericArguments
确定泛型参数类型是"SomeType".
////// Checks whether this type has the specified definition in its ancestry. /// public static bool HasGenericDefinition(this Type type, Type definition) { return GetTypeWithGenericDefinition(type, definition) != null; } ////// Returns the actual type implementing the specified definition from the /// ancestry of the type, if available. Else, null. /// 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; }