406

To check if a type is a subclass of another type in C#, it's easy:

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

However, this will fail:

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

Is there any way to check whether a type is either a subclass OR of the base class itself, without using an OR operator or using an extension method?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Daniel T.
  • 37,212
  • 36
  • 139
  • 206

5 Answers5

611

Apparently, no.

Here's the options:

Type.IsSubclassOf

As you've already found out, this will not work if the two types are the same, 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

Which indicates that Derived is a subclass of Base, but that Baseis (obviously) not a subclass of itself.

Type.IsAssignableFrom

Now, this will answer your particular question, but it will also give you false positives. As Eric Lippert has pointed out in the comments, while the method will indeed return True for the two above questions, it will also return True for these, which you probably 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 you get the following output:

True
True
True

The last True there would indicate, if the method only answered the question asked, that uint[] inherits from int[] or that they're the same type, which clearly is not the case.

So IsAssignableFrom is not entirely correct either.

is and as

The "problem" with is and as in the context of your question is that they will require you to operate on the objects and write one of the types directly in code, and not work with Type objects.

In other words, 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

Conclusion

While the above methods might fit your needs, the only correct answer to your question (as I see it) is that you will need an extra check:

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

which of course makes more sense in a method:

public bool IsSameOrSubclass(Type potentialBase, Type potentialDescendant)
{
    return potentialDescendant.IsSubclassOf(potentialBase)
           || potentialDescendant == potentialBase;
}
Andrea Colleoni
  • 5,919
  • 3
  • 30
  • 49
Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
  • 2
    Thanks! I'll mark this as the correct answer (gotta wait 8 more minutes) since you mentioned that the check has to be reversed and provided a link to the MSDN documentation. – Daniel T. Apr 30 '10 at 04:30
  • 83
    Note that this doesn't actually do what the question asked for; this does not determine whether one type is a subclass of another, but rather whether one type is assignment compatible with another. An array of uint isn't a subclass of an array of int, but they are assignment compatible. IEnumerable isn't a subclass of IEnumerable, but they are assignment compatible in v4. – Eric Lippert Apr 30 '10 at 06:07
  • 3
    How would `IsInstanceOfType` fit into this? – Lennart Jul 18 '16 at 07:40
  • why does `typeof(List).IsSubclassOf(typeof(IList))` return false? – Nilesh Barai Oct 25 '19 at 08:25
  • 1
    @NileshBarai Because a class is not a *subclass* of an interface it *implements*. Use `typeof(Test).GetInterfaces().Contains(typeof(ITest))` to test if a class implements an interface, or `typeof(ITest).IsAssignableFrom(typeof(Test))` – Lasse V. Karlsen Oct 25 '19 at 11:12
43
typeof(BaseClass).IsAssignableFrom(unknownType);
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
12

You should try using Type.IsAssignableFrom instead.

Thomas
  • 63,911
  • 12
  • 95
  • 141
1

If you're trying to do it in a Xamarin Forms PCL project, the above solutions using IsAssignableFrom gives an error:

Error: 'Type' does not contain a definition for 'IsAssignableFrom' and no extension method 'IsAssignableFrom' accepting a first argument of type 'Type' could be found (are you missing a using directive or an assembly reference?)

because IsAssignableFrom asks for a TypeInfo object. You can use the GetTypeInfo() method from System.Reflection:

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

Bruno Serrano
  • 555
  • 1
  • 4
  • 13
0

I'm posting this answer with the hope of someone sharing with me if and why it would be a bad idea. In my application, I have a property of Type that I want to check to be sure it is typeof(A) or typeof(B), where B is any class derived from A. So 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 feel like I might be a bit naive here so any feedback would be welcome.

baskren
  • 963
  • 8
  • 19
  • 4
    There are a couple of issues with that idea: 1) the type needs a parameterless constructor or CreateInstance will fail; 2) casting to (A) doesn't return null if the cast can't be made, it throws; 3) you don't actually need the new instance, so you have a useless allocation. The accepted answer is better (though not perfect). – Marcel Popescu Dec 07 '17 at 19:37
  • Thanks for the feedback. Very helpful. – baskren Dec 08 '17 at 20:35