代码之家  ›  专栏  ›  技术社区  ›  bernhardrusch

检查类是否从泛型类派生

  •  274
  • bernhardrusch  · 技术社区  · 16 年前

    我的项目中有一个带有派生类的泛型类。

    public class GenericClass<T> : GenericInterface<T>
    {
    }
    
    public class Test : GenericClass<SomeType>
    {
    }
    

    有没有办法知道 Type 对象派生自 GenericClass ?

    t.IsSubclassOf(typeof(GenericClass<>))
    

    不起作用。

    16 回复  |  直到 7 年前
        1
  •  386
  •   xanadont    12 年前

    试试这个代码

    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;
    }
    
        2
  •  86
  •   EnocNRoll - AnandaGopal Pardue    16 年前

    (由于大量重写而重新发布)

    Jaredpar的代码答案非常好,但是我有一个提示,如果您的泛型类型不基于值类型参数,那么它就不必要了。我被挂断了为什么“is”操作员不工作,所以我还记录了我的实验结果,以备将来参考。请加强此答案以进一步提高其清晰度。

    提示:

    如果确保泛型类实现继承自抽象的非泛型基类(如GenericClassBase),则可以毫无困难地问相同的问题:

    typeof(Test).IsSubclassOf(typeof(GenericClassBase))
    

    IsSub类()

    我的测试表明issubclassof()不适用于无参数泛型类型,例如

    typeof(GenericClass<>)
    

    但是它将与

    typeof(GenericClass<SomeType>)
    

    因此,如果您愿意基于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);
    

    另一方面,如果您想要一些特定于泛型类的东西,我想您可以使它更具体一些,如下所示:

    bool IsTypeofGenericClass<SomeType>(object t)
    {
        return (t is GenericClass<SomeType>);
    }
    

    然后您要测试如下:

    bool test1 = IsTypeofGenericClass<SomeType>(t);
    
        3
  •  33
  •   David Schmitt    13 年前

    我仔细检查了其中一些样品,发现在某些情况下它们是不足的。此版本适用于各种泛型:类型、接口及其类型定义。

    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);
    }
    
        4
  •  20
  •   Xav987    9 年前

    在我看来,这种实现在更多情况下都可以工作(无论是否有启动的参数,无论子级和参数的数量如何,都是通用类和接口):

    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;
        }
    }
    

    这是我的 七十 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<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");
    }
    

    测试的类和接口:

    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 { }
    
        5
  •  9
  •   user53564    16 年前

    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);
        }
    }
    
        6
  •  9
  •       15 年前

    下面是我创建的一个小方法,用于检查对象是否从特定类型派生。对我来说太好了!

    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);
    }
    
        7
  •  7
  •   nawfal Donny V.    11 年前

    它可能有点杀伤力,但我使用如下扩展方法。它们检查接口和子类。它还可以返回具有指定泛型定义的类型。

    例如,对于问题中的示例,它可以针对通用接口和通用类进行测试。返回的类型可用于 GetGenericArguments 确定泛型参数类型为“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;
    }
    
        8
  •  4
  •   Menno Deij - van Rijswijk    11 年前

    基于上面Fir3rpho3nixx和David Schmitt给出的优秀答案,我修改了他们的代码,并添加了shouldinheritalimplementtypedgenericinterface测试(最后一个)。

        /// <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>)));
        } 
    
        9
  •  4
  •   DVK    9 年前

    这一切都可以用LINQ轻松完成。这将找到属于泛型基类GenericBaseType子类的任何类型。

        IEnumerable<Type> allTypes = Assembly.GetExecutingAssembly().GetTypes();
    
        IEnumerable<Type> mySubclasses = allTypes.Where(t => t.BaseType != null 
                                                                && t.BaseType.IsGenericType
                                                                && t.BaseType.GetGenericTypeDefinition() == typeof(GenericBaseType<,>));
    
        10
  •  4
  •   kad81    7 年前

    简单的解决方案:只需创建第二个非泛型接口并将其添加到泛型类:

    public interface IGenericClass
    {
    }
    
    public class GenericClass<T> : GenericInterface<T>, IGenericClass
    {
    }
    

    然后用你喜欢的任何方式检查一下 is , as , IsAssignableFrom 等。

    if (thing is IGenericClass)
    {
        // Do work
    {
    

    显然,只有当您有能力编辑泛型类(OP似乎有)时才可能,但是它比使用一个神秘的扩展方法更优雅和易读。

        11
  •  4
  •   johnny 5    7 年前

    添加到@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);
    }
    

    前任:

    Console.WriteLine(typeof(IList<>).IsSubTypeOfRawGeneric(typeof(IList<int>))); // true
    
        12
  •  2
  •   Cirem    15 年前

    JaredPar

    如果我将typeof(type<gt;)作为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;
    }
    
        13
  •  1
  •   Ken Kin    7 年前

    @EnocnRoll-Ananda Gopal的答案很有趣,但是如果一个实例没有预先实例化,或者您想要检查一个泛型类型定义,我建议使用以下方法:

    public static bool TypeIs(this Type x, Type d) {
        if(null==d) {
            return false;
        }
    
        for(var c = x; null!=c; c=c.BaseType) {
            var a = c.GetInterfaces();
    
            for(var i = a.Length; i-->=0;) {
                var t = i<0 ? c : a[i];
    
                if(t==d||t.IsGenericType&&t.GetGenericTypeDefinition()==d) {
                    return true;
                }
            }
        }
    
        return false;
    }
    

    使用方式如下:

    var b = typeof(char[]).TypeIs(typeof(IList<>)); // true
    

    有四种条件的情况 t (待测试)和 d 一般类型和两种情况 t==d 哪些是 (1)既不 T 也不 D 是一般定义 (2)两者都是通用定义。 . 只有当 D 已经是我们有机会说的一般定义了 T 是一个 D 但反之亦然。

    它应该与您想要测试的任意类或接口一起工作,并返回类似于使用 is 操作员。

        14
  •  0
  •   Patrick Rudzitis    15 年前
    Type _type = myclass.GetType();
    PropertyInfo[] _propertyInfos = _type.GetProperties();
    Boolean _test = _propertyInfos[0].PropertyType.GetGenericTypeDefinition() 
    == typeof(List<>);
    
        15
  •  0
  •   Yaseen    8 年前

    你可以试试这个分机

        public static bool IsSubClassOfGenericClass(this Type type, Type genericClass,Type t)
        {
            return type.IsSubclassOf(genericClass.MakeGenericType(new[] { t }));
        }
    
        16
  •  0
  •   isandburn    8 年前

    比赛进行得太晚了…我也有另一种贾洛德帕的回答。

    这里是类型。问题B(类型)反射镜的类别:

        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;
        }
    

    从这一点上,我们看到它并没有做任何过于疯狂的事情,它类似于Jaredpar的迭代方法。到目前为止,一切都很好。这是我的版本(免责声明:没有经过彻底测试,所以我知道如果你发现问题)

        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;
        }
    

    基本上,这只是System.Type的一个扩展方法-我这样做是为了有意将“thisType”类型限制为具体类型,因为我的直接用法是对类型对象执行linq查询“where”谓词。我敢肯定,如果你需要的话,所有聪明的人都能找到一种高效的、多用途的静态方法:)代码做了一些事情,但答案的代码没有。

    1. 开放到一般的“扩展”——我正在考虑继承(思考类) 以及实现(接口);方法和参数名称 改变以更好地反映这一点
    2. 输入空验证(MEAH)
    3. 相同类型的输入(类不能扩展自身)
    4. 如果有问题的类型是接口,则执行短路;因为getInterfaces()返回所有已实现的接口(即使是在超级类中实现的接口),所以您可以简单地循环该集合,而不必攀爬继承树。

    其余基本上与Jaredpar的代码相同