Check if a class is derived from a generic class

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

    It seems to me that this implementation works in more cases (generic class and interface with or without initiated parameters, regardless of the number of child and parameters):

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

    Here are my 70 76 test cases:

    [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");
    }
    

    Classes and interfaces for testing :

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

提交回复
热议问题