Check if a class is derived from a generic class

前端 未结 16 1364
太阳男子
太阳男子 2020-11-22 09:57

I have a generic class in my project with derived classes.

public class GenericClass : GenericInterface
{
}

public class Test : GenericCla         


        
相关标签:
16条回答
  • 2020-11-22 10:16

    It might be overkill but I use extension methods like the following. They check interfaces as well as subclasses. It can also return the type that has the specified generic definition.

    E.g. for the example in the question it can test against generic interface as well as generic class. The returned type can be used with GetGenericArguments to determine that the generic argument type is "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;
    }
    
    0 讨论(0)
  • 2020-11-22 10:16

    JaredPar,

    This did not work for me if I pass typeof(type<>) as toCheck. Here's what I changed.

    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;
    }
    
    0 讨论(0)
  • 2020-11-22 10:19

    Building on the excellent answer above by fir3rpho3nixx and David Schmitt, I have modified their code and added the ShouldInheritOrImplementTypedGenericInterface test (last one).

        /// <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>)));
        } 
    
    0 讨论(0)
  • 2020-11-22 10:19

    @EnocNRoll - Ananda Gopal 's answer is interesting, but in case an instance is not instantiated beforehand or you want to check with a generic type definition, I'd suggest this method:

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

    and use it like:

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

    There are four conditional cases when both t(to be tested) and d are generic types and two cases are covered by t==d which are (1)neither t nor d is a generic definition or (2) both of them are generic definitions. The rest cases are one of them is a generic definition, only when d is already a generic definition we have the chance to say a t is a d but not vice versa.

    It should work with arbitrary classes or interfaces you want to test, and returns what as if you test an instance of that type with the is operator.

    0 讨论(0)
  • 2020-11-22 10:22

    Here's a little method I created for checking that a object is derived from a specific type. Works great for me!

    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);
    }
    
    0 讨论(0)
  • 2020-11-22 10:22

    You can try this extension

        public static bool IsSubClassOfGenericClass(this Type type, Type genericClass,Type t)
        {
            return type.IsSubclassOf(genericClass.MakeGenericType(new[] { t }));
        }
    
    0 讨论(0)
提交回复
热议问题