Check if a class is derived from a generic class

前端 未结 16 1391
太阳男子
太阳男子 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:23

    JaredPar's code works but only for one level of inheritance. For unlimited levels of inheritance, use the following code

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

    I worked through some of these samples and found they were lacking in some cases. This version works with all kinds of generics: types, interfaces and type definitions thereof.

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

    Here are the unit tests also:

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

    Simple solution: just create and add a second, non-generic interface to the generic class:

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

    Then just check for that in any way you like using is, as, IsAssignableFrom, etc.

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

    Obviously only possible if you have the ability to edit the generic class (which the OP seems to have), but it's a bit more elegant and readable than using a cryptic extension method.

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

    Added to @jaredpar's answer, here's what I use to check for interfaces:

    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
    
    0 讨论(0)
提交回复
热议问题