Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test whether two generics have a base-subclass relationship without instantiating them?

I have the following generic classes:

class Base<T> where T : ... { ... }
class Derived<T> : Base<T> where T : ... { ... }
class Another<T> where T : ... { ... }
class DerivedFromDerived<T> : Derived<T> where T : ... { ... }

Somewhere in my code, I would like to test whether a given generic inherits from Base<T>, without creating a particular instance of the generic. How do I do that?

static bool DerivedFromBase(Type type) { /* ??? */ }

static void Main(string[] args)
{
    Console.WriteLine(DerivedFromBase(typeof(Derived<>)));            // true
    Console.WriteLine(DerivedFromBase(typeof(Another<>)));            // false
    Console.WriteLine(DerivedFromBase(typeof(DerivedFromDerived<>))); // true
    Console.ReadKey(true);
}

EDIT: Thank you Mark. Now I see the light. I originally tried the following:

typeof(Derived<>).BaseType == typeof(Base<>)

Apparently, this is correct. But it is not. The problem is that Base's T is not the same thing as Derived's T. So, in

typeof(Base<>)

Base's T is a free type. But, in

typeof(Derived<>).BaseType

Base's T is bound to Derived's T, which is in turn a free type. (This is so awesome I would LOVE to see the System.Reflection's source code!) Now,

typeof(Derived<>).BaseType.GetGenericTypeDefinition()

unbounds Base's T. Conclusion:

typeof(Derived<>).BaseType.GetGenericTypeDefinition() == typeof(Base<>)

And now, if you all excuse me, my head is burning.

like image 253
pyon Avatar asked Apr 08 '11 22:04

pyon


1 Answers

Not sure if this is what you are looking for but I think "IsAssignableFrom" will do the trick.

class Program
{
    class Base<T> { }
    class Derived<T> : Base<T> { }
    class Another<T> { }
    class DerivedFromDerived<T> : Derived<T> { }

    static bool DerivedFromBase<T>(Type type)
    {
        return typeof(Base<T>).IsAssignableFrom(type);
    }

    static void Main(string[] args)
    {
        Console.WriteLine(DerivedFromBase<int>(typeof(Derived<int>)));            // true    
        Console.WriteLine(DerivedFromBase<int>(typeof(Another<int>)));            // false    
        Console.WriteLine(DerivedFromBase<int>(typeof(DerivedFromDerived<int>))); // true   
        Console.ReadKey(true);
    }
}

To handle the open base type:

static bool DerivedFromBase(Type type)
    {
        Type openBase = typeof(Base<>);

        var baseType = type;

        while (baseType != typeof(Object) && baseType != null)
        {
            if (baseType.GetGenericTypeDefinition() == openBase) return true;

            baseType = baseType.BaseType;
        }
        return false;
    }
like image 149
MarkPflug Avatar answered Nov 09 '22 12:11

MarkPflug