Reputation: 31924
I need to test if a value is an instance of a generic base class, without knowing the generic type parameter. Using the MSDN example as the base of my example, this is what I'd like to accomplish:
using System;
public class Class1<T> { }
public class DerivedC1 : Class1<int> { }
class IsSubclassTest
{
public static void Main()
{
Console.WriteLine(
"DerivedC1 subclass of Class1: {0}",
typeof(DerivedC1).IsSubclassOf(typeof(Class1<>)) // <- Here.
);
}
}
While this is syntactically correct, it always yields false. If I remove the generic type parameter, it works as expected (returns true).
How can I test if a class type is a subclass of a generic base class, without knowing its generic type parameter as such?
Upvotes: 11
Views: 8643
Reputation: 120380
There's special methods on Type
for this sort of thing. As far as I can see, you'll need to walk up your base-types and check each in turn until you either (a) hit a match or (b) get to the top of the inheritance hierarchy (i.e. System.Object
).
As such, the following (recursive) extension method:
public static class TypeExtensions
{
public static bool IsDerivedFromGenericParent(this Type type, Type parentType)
{
if(!parentType.IsGenericType)
{
throw new ArgumentException("type must be generic", "parentType");
}
if(type == null || type == typeof(object))
{
return false;
}
if(type.IsGenericType && type.GetGenericTypeDefinition() == parentType)
{
return true;
}
return type.BaseType.IsDerivedFromGenericParent(parentType)
|| type.GetInterfaces().Any(t=>t.IsDerivedFromGenericParent(parentType));
}
}
will allow you to do the following
typeof(DerivedC1).IsDerivedFromGenericParent(typeof(Class1<>))
...and will also work if you test something derived from DerivedC1
.
Upvotes: 5
Reputation: 64933
Changing typeof(DerivedC1).IsSubclassOf(typeof(Class1<>))
to typeof(Class1<>).IsAssignableFrom(typeof(DerivedC1).BaseType.GetGenericTypeDefinition())
should be enough in your case.
Type.IsAssignableFrom
is more powerful than using Type.IsSubClassOf
because it just checks if some type is assignable to other type. This includes, the same type, interface types and other cases.
Upvotes: 6
Reputation: 32740
The problem is that DrevidedC1
is not a sublcass of Class1<T>
, it's a subclass of Class1<int>
. Make sure you understand this subtle diference; Class1<T>
is a open type (T
can be anything, it hasn't been set) while DerivedC1
extends a closed type Class1<int>
(it's not open in T
anymore, T
is set to int
and only int
). So when you do the following:
typeof(DerivedC1).IsSubclassOf(typeof(Class1<>))
The answer is evidently false
.
What you need to do is check if the generic type definition of DerivedC1
's base type (think of it as the corresponding open generic type of Class1<int>
) equals Class1<T>
which it clearly does.
The correct code is therefore:
typeof(DerivedC1).BaseType.GetGenericTypeDefinition() == typeof(Class1<>));
Or better yet, as Matías Fidemraizer states in his answer:
typeof(DerivedC1).BaseType.GetGenericTypeDefinition().IsAssignableFrom(typeof(Class1<>)));
Upvotes: 23