Search code examples
c#.netinheritancereflectiontypeinfo

Class not inheriting from object?


I am working on a method that is using reflection to inspect parameter types of methods. This methods iterates through the ParameterInfo's and is doing something with the types of those parameters.

I was always under the assumption that if TypeInfo.IsClass is true, that this type is a class and always derives (indirectly) from type object (except when the type is object itself of course). So, if TypeInfo.IsClass is true, TypeInfo.BaseType must be set.

Well my assumption was wrong! There are classes that do NOT derive from type object. And my assumption messed up my code.

For example:

Type type = typeof(int).MakeByRefType();

type.IsClass will be true and type.BaseType will be null.

If you think about it, it is logical. And I can prevent my code to crash by checking TypeInfo.IsByRef.

Now my question is: are there more such 'exotic' types (besided the ByRef-types and type object) which are a class (IsClass == true) but do not have a base type (BaseType == null)?

Before you answer: I am only refering to types where IsClass == true! And my example with type int was just an example. It could have been any type. So please no:

  • Interfaces
  • Structs
  • Void

Answers so far:

  • ByRef types (T&): as descrybed in the question.
  • Pointer types (T*): Found by Mark Gravell.

Solution

  • I would say that IsClass is simply misleading here. It states:

    Gets a value indicating whether the System.Type is a class; that is, not a value type or interface.

    and it is implemented this way: it checks whether the flags include Interface, and whether it is a ValueType.

    Unfortunately, there are more things that this. Pointers are not managed types. A by-ref is very similar to a pointer. Pointer are not objects, although in common use the cast is actually a de-reference/cast. The same applies for things like direct pointers such as int*.

    Not everything in .NET is an object :)

    var baseType = typeof(int*).BaseType; // null
    bool liesAndMoreLies = typeof(int*).IsClass; // true
    

    Eric Lippert covers this more here: Not everything derives from object - and lists a few other examples (open generic types, for example).