Type.IsSubclssOf and Type.IsAssignableFrom

On the Type class there are two very use­ful meth­ods which allows you to deter­mine the inher­i­tance rela­tion­ship of two arbi­trary types at run­time – IsSub­clas­sOf method and IsAs­sign­a­ble­From method.

IsSubclassOf

The MSDN doc­u­men­ta­tion for the IsSub­clas­sOf method states:

Deter­mines whether the class rep­re­sent­ed by the cur­rent Type derives from the class rep­re­sent­ed by the spec­i­fied Type.

   1: public class ClassA { }

   2: public class ClassB : ClassA { }

   3: public class ClassC : ClassB { }

   4: ...

   5: Console.WriteLine(typeof(ClassB).IsSubclassOf(typeof(ClassA))); // TRUE

   6: Console.WriteLine(typeof(ClassB).IsSubclassOf(typeof(ClassB))); // FALSE

   7: Console.WriteLine(typeof(ClassB).IsSubclassOf(typeof(ClassC))); // FALSE

   8: Console.WriteLine(typeof(ClassC).IsSubclassOf(typeof(ClassA))); // TRUE

   9: Console.WriteLine(typeof(ClassC).IsSubclassOf(typeof(ClassB))); // TRUE

Pret­ty use­ful, eh? How­ev­er, it doesn’t work when it comes to inter­faces:

The IsSub­clas­sOf method can­not be used to deter­mine whether an inter­face derives from anoth­er inter­face, or whether a class imple­ments an inter­face.

   1: public interface ID { }

   2: public interface IE : ID { }

   3:

   4: public class ClassD : ID { }

   5:

   6: Console.WriteLine(typeof(ClassD).IsSubclassOf(typeof(ID))); // FALSE

   7: Console.WriteLine(typeof(IE).IsSubclassOf(typeof(ID));      // FALSE

Ok, roger that, but what about gener­ics? Let’s see..

   1: public class ClassF<T> { }

   2: public class ClassG<T> : ClassF<T> { }

   3: public class ClassH : ClassF<int> { }

   4:

   5: // no type constraint, no good

   6: Console.WriteLine(typeof(ClassG<>).IsSubclassOf(typeof(ClassF<>)));             // FALSE

   7:

   8: // no covariance support here

   9: Console.WriteLine(typeof(string).IsSubclassOf(typeof(object)));                 // TRUE

  10: Console.WriteLine(typeof(ClassG<string>).IsSubclassOf(typeof(ClassF<object>))); // FALSE

  11:

  12: // type constraint has to match

  13: Console.WriteLine(typeof(ClassG<int>).IsSubclassOf(typeof(ClassF<int>)));       // TRUE

  14: Console.WriteLine(typeof(ClassH).IsSubclassOf(typeof(ClassF<int>)));            // TRUE

  15: Console.WriteLine(typeof(ClassH).IsSubclassOf(typeof(ClassF<long>)));           // FALSE

IsAssignableFrom

The MSDN doc­u­men­ta­tion for the IsAs­sign­a­ble­From method states:

Deter­mines whether an instance of the cur­rent Type can be assigned from an instance of the spec­i­fied Type.

The IsAs­sign­a­ble­From method basi­cal­ly works the same way as the is oper­a­tor and does a sim­ple assign­ment com­pat­i­bil­i­ty test to see if a vari­able of type A can be assigned with a vari­able of type B. Unlike the IsSub­clas­sOf method, it also works for inter­faces and remem­ber, if typeof(B).IsSubclassOf(typeof(A)) is true then typeof(A).IsAssignableFrom(typeof(B)) is also true.

   1: Console.WriteLine(typeof(IA).IsAssignableFrom(typeof(IB)));            // TRUE

   2: Console.WriteLine(typeof(IA).IsAssignableFrom(typeof(IA)));            // TRUE

   3: Console.WriteLine(typeof(IB).IsAssignableFrom(typeof(IA)));            // FALSE

   4: Console.WriteLine(typeof(IA).IsAssignableFrom(typeof(ClassA)));        // TRUE

   5: Console.WriteLine(typeof(ClassA).IsAssignableFrom(typeof(ClassB)));    // TRUE

Again, let’s con­sid­er the gener­ics case:

   1: // no type constraint, still no good

   2: Console.WriteLine(typeof(ClassF<>).IsAssignableFrom(typeof(ClassG<>)));    // FALSE

   3:

   4: // note: whilst you can't specify generic variance on the class definition you can do it on the 

   5: // interface, e.g. IEnumerable<out T>, so we're able to do the following test

   6: Console.WriteLine(typeof(object).IsAssignableFrom(typeof(string)));        // TRUE

   7: Console.WriteLine(typeof(IEnumerable<object>).IsAssignableFrom(typeof(IEnumerable<string>))); // TRUE

Performance Overheads

In gen­er­al, doing reflec­tion is an expen­sive busi­ness and you should always be mind­ful of the poten­tial per­for­mance hit you get if you have to do lots of reflec­tion in your code.

I can’t think of too many places where you’d need to repeat­ed­ly test if one type is sub­class of/can be assigned from anoth­er type but nonethe­less, out of pure curios­i­ty, I decid­ed to give it a test and see what sort of per­for­mance over­head these two meth­ods car­ry and here are the results:

Test: exe­cute 100000 times

Method call Return val­ue Avg time tak­en (mil­lisec­onds) over 3 tries
typeof(ClassB).IsSubclassOf(ClassA) TRUE 6
typeof(ClassB).IsSubclassOf(typeof(ClassH)) FALSE 16
typeof(ClassA).IsSubclassOf(typeof(IA)) FALSE 11
typeof(IA).IsAssignableFrom(typeof(IB)) TRUE 6
typeof(ClassB).IsAssignableFrom(typeof(ClassH)) FALSE 6
typeof(IA).IsAssignableFrom(typeof(ClassH)) FALSE 6

Notice that with the IsSub­clas­sOf method there’s notice­able dif­fer­ence in aver­age run time between cas­es that returns true and those that return false. Whilst the IsAs­sign­a­ble­From method con­sis­tent­ly runs at 6 mil­lisec­onds.

How­ev­er, giv­en the small amount of time tak­en to exe­cute each check 100000 times the morale of this sto­ry is real­ly “Don’t lose any sleep over it”!