I have a generic class in my project with derived classes.
public class GenericClass : GenericInterface
{
}
public class Test : GenericCla
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 { }