Coder Perfect

How can I tell if a type is a subtype or an object type?

Problem

It’s simple to see if a type is a subclass of another type in C#:

typeof (SubClass).IsSubclassOf(typeof (BaseClass)); // returns true

This, however, will fail:

typeof (BaseClass).IsSubclassOf(typeof (BaseClass)); // returns false

Is there a way to determine whether a type is a subclass OR the base class itself without using the OR operator or an extension method?

Asked by Daniel T.

Solution #1

Apparently, no.

Here’s the options:

As you’ve already discovered, if the two types are the identical, this won’t work. Here’s a sample LINQPad program that demonstrates:

void Main()
{
    typeof(Derived).IsSubclassOf(typeof(Base)).Dump();
    typeof(Base).IsSubclassOf(typeof(Base)).Dump();
}

public class Base { }
public class Derived : Base { }

Output:

True
False

This means that Derived is a subclass of Base, but that Base is not a subclass of itself (clearly).

This will provide you with an answer to your specific inquiry, but it will also provide you with false positives. While the method will return True for the two questions above, as Eric Lippert pointed out in the comments, it will also return True for the following, which you definitely don’t want:

void Main()
{
    typeof(Base).IsAssignableFrom(typeof(Derived)).Dump();
    typeof(Base).IsAssignableFrom(typeof(Base)).Dump();
    typeof(int[]).IsAssignableFrom(typeof(uint[])).Dump();
}

public class Base { }
public class Derived : Base { }

Here’s what you’ll get as a result:

True
True
True

If the method just answered the question, the last True there would indicate that uint[] inherits from int[] or that they’re the same type, which is clearly not the case.

As a result, IsAssignableFrom isn’t totally accurate.

The “issue” with is and as in the context of your query is that they force you to interact with objects and write one of the kinds directly in code rather than using Type objects.

To put it another way, this won’t compile:

SubClass is BaseClass
^--+---^
   |
   +-- need object reference here

nor will this:

typeof(SubClass) is typeof(BaseClass)
                    ^-------+-------^
                            |
                            +-- need type name here, not Type object

nor will this:

typeof(SubClass) is BaseClass
^------+-------^
       |
       +-- this returns a Type object, And "System.Type" does not
           inherit from BaseClass

While the approaches listed above may meet your needs, the only accurate response to your query (in my opinion) is that you will require an additional check:

typeof(Derived).IsSubclassOf(typeof(Base)) || typeof(Derived) == typeof(Base);

It is, of course, more logical in a method:

public bool IsSameOrSubclass(Type potentialBase, Type potentialDescendant)
{
    return potentialDescendant.IsSubclassOf(potentialBase)
           || potentialDescendant == potentialBase;
}

Answered by Lasse V. Karlsen

Solution #2

typeof(BaseClass).IsAssignableFrom(unknownType);

Answered by Marc Gravell

Solution #3

You should give Type a go. Instead, use IsAssignableFrom.

Answered by Thomas

Solution #4

If you try to do it with IsAssignableFrom in a Xamarin Forms PCL project, you’ll get the following error:

IsAssignableFrom necessitates the use of a TypeInfo object. You can utilize System’s GetTypeInfo() function. Reflection:

typeof(BaseClass).GetTypeInfo().IsAssignableFrom(typeof(unknownType).GetTypeInfo())

Answered by Bruno Serrano

Solution #5

I’m publishing this answer in the hopes of hearing from someone who can tell me if and why this is a poor idea. I have a Type property in my application that I want to make sure is typeof(A) or typeof(B), where B is any class derived from A. So here’s my code:

public class A
{
}

public class B : A
{
}

public class MyClass
{
    private Type _helperType;
    public Type HelperType
    {
        get { return _helperType; }
        set 
        {
            var testInstance = (A)Activator.CreateInstance(value);
            if (testInstance==null)
                throw new InvalidCastException("HelperType must be derived from A");
            _helperType = value;
        }
    }
}

I’m afraid I’m being a little naive here, so any input would be very appreciated.

Answered by baskren

Post is based on https://stackoverflow.com/questions/2742276/how-do-i-check-if-a-type-is-a-subtype-or-the-type-of-an-object