IsInstanceOfTypeFamily – Check whether a given type is a member of a “type family”

Well, my first article in my brand new blog. Thanks go out to Hendrik Lösch, since his question on codekicker.de was my initial motivation to start my own blog. Why is that? In my opinion, lots of answers on codekicker.de can serve the purpose of helping the person who initially asked the question in a clear and straight forward way. This is good and this is why I like codekicker.de. Nevertheless some questions inspire me in thinking or re-thinking a certain topic and make my brain elaborate on it – regardless of whether I want that or not. For my own benefit I decided to blog about these thoughts – just to capture some of my “neuronal elaboration” and have a place for later reference. I also decided to blog in English language, since in my opinion it is more compact and lacks those ugly 27-syllables German nouns that are often (mis)used instead of a sentence.

Enough of my personal sissy stuff, let’s get back to facts here. The question that motivated this blog post was like “How to determine if an object is of a generic type” (regarding .NET framework, specifically C# in this case).

At first glance this question made myself think about the different semantics the term “generic type” brings up (I like to reflect on things that superficially seem to be daily business but actually prove they are not when diving deeper). What is a generic type and why do built-in type comparisons fail or just don’t compile in some circumstances? What’s wrong? For an answer to this question I have to elaborate on the differences between the semantics the term “generic type” incorporates by assigning names that have been (most probably) initially documented and intended by the language/runtime designers. The ultimate goal of this post is to provide an extension method with the following signature:

public static bool IsInstanceOfTypeFamily(this System.Type type, object o);

This idea is different from my first thoughts to provide an extension method called Is with the following signature, effectively re-using the name of a built-in type check in C# (is operator):

public static bool Is(this object o, System.Type type);

Since the semantic of the existing ‘is’ is definitely different, I decided to find another approach (because reusing an existing term and assigning a different semantic is almost never a good idea). System.Type has a method called IsInstanceOfType and this method finally inspired me to wrap this whole topic up in a method called IsInstanceOfTypeFamily. Since they gave us extension methods we can happily glue this functionality to  System.Type. Before we get to the actual implementation, it is essential to reflect on the underlying concepts and come up with a contract for this new extension method.

Generic type definition

When looking at MSDN, we discover this definition:

A generic type definition is a template from which other types can be constructed.

Given that definition, valid examples of generic type definitions in C# are

Foo<>, Bar<, >, FooBar<, , , >

Note the commas between the brackets, from those you can count the number of generic type parameters. It is these defintions that make up a set of types I decided to call a type family. One can use System.Type.IsGenericTypeDefinition to figure this out.

Open constructed generic type

As long as a generic type carries around a type parameter, it is called an open constructed generic type. So Foo<T>, Bar<T, U> are open constructed generic types. Subclassing and providing not all generic type parameters again creates open constructed types. E.g.

class OnlyDerivedBar<T,U> : Bar<T,U>
class HalfBakedBar<T> : Bar<T, string>

System.Type.ContainsGenericParameters will return true for an open generic type.

Closed constructed generic type

The act of providing concrete types for each type parameter of a generic type is called closing. Examples for closed constructed generic types are Foo<int>, Bar<int,string> as well as subclasses of them.

System.Type.ContainsGenericParameters will return false for a closed generic type.

IsInstanceOfTypeFamily – extension method

As promised at the beginning of this post, I will provide some code for an extension method here, that has the same contract as the existing System.Type.IsInstanceOfType(object o) method but works for type families instead of concrete types. The documentation of the return value at MSDN defines the contract of the method:

[…]true if the current Type is in the inheritance hierarchy of the object represented by o, or if the current Type is an interface that o supports. false if neither of these conditions is the case, or if o is null, or if the current Type is an open generic type (that is, ContainsGenericParameters returns true).

Interesting enough, a little side note at MSDN then comes up with a justification for Hendrik’s question and my extension method:

A constructed type is not an instance of its generic type definition.

So, let’s define the contract of our new extension method.

IsInstanceOfTypeFamily – Contract

Return true, if the System.Type passed in returns true for a call to ContainsGenericParameters and

  • the current (class) type family can be found in the inheritance hierarchy of the object to check
  • at least one interface supported by the object to check is in the current (interface) type family

Return false

  • in all other cases.

So I come up with this

Implementation

public static bool IsInstanceOfTypeFamily(this Type typeFamily, object o)
{
    bool result = false;

    if (o != null && typeFamily.ContainsGenericParameters)
    {
        Type objectType = o.GetType();
        Type genericTypeDefinition = typeFamily.GetGenericTypeDefinition();

        if (genericTypeDefinition.IsClass)
        {
            // objectType and its base types must be inspected
            result = objectType.AnyInheritedClassInTypeFamily(genericTypeDefinition);
        }
        else if (genericTypeDefinition.IsInterface)
        {
            // all interfaces implemented by objectType as well as their inheritance hierarchy have to be inspected
            result = objectType.GetInterfaces()
                                .Any(interfaceType => interfaceType.AnyInheritedInterfaceInTypeFamily(genericTypeDefinition));
        }
        else if (genericTypeDefinition.IsValueType)
        {
            // objectType (not its base classes, since retrieving inherited interfaces does not work the same way as retrieving base types)
            // and all interfaces implemented by objectType as well as their inheritance hierarchy have to be inspected
            if (objectType.IsGenericType)
                result = objectType.GetGenericTypeDefinition().Equals(genericTypeDefinition);

            if(!result)
                result = objectType.GetInterfaces()
                                .Any(interfaceType => interfaceType.AnyInheritedInterfaceInTypeFamily(genericTypeDefinition));
        }
        else
        {
            // just in case...
            System.Diagnostics.Debug.Fail("Forgot a case? Maybe implementation is not complete.");
            throw new NotSupportedException("Unsupported case. Maybe implementation is not complete.");
        }
    }

    return result;
}

There are two little supporting methods that I have implemented:

private static bool AnyInheritedInterfaceInTypeFamily(this Type interfaceTypeToCheck, Type typeFamily)
{
    bool result = false;

    if (interfaceTypeToCheck.IsGenericType)
        result = interfaceTypeToCheck.GetGenericTypeDefinition().Equals(typeFamily);

    if(!result)
    {
        // proceed with inherited interfaces and inheritance hierarchy of each
        result = interfaceTypeToCheck.GetInterfaces()
                                .Any(interfaceType => interfaceType.AnyInheritedInterfaceInTypeFamily(typeFamily));
    }

    return result;
}

private static bool AnyInheritedClassInTypeFamily(this Type classTypeToCheck, Type typeFamily)
{
    bool result = false;
    Type baseType = classTypeToCheck;

    while (baseType != typeof(object))
    {
        if (baseType.IsGenericType)
        {
            Type baseTypeFamily = baseType.GetGenericTypeDefinition();
            result = baseTypeFamily.Equals(typeFamily);
            if (result)
                break;
        }

        baseType = baseType.BaseType;
    }

    return result;
}

I ran some little smoke tests and it seems to work so far. I will update this post in the next days and provide a set of unit tests as well as a complete VisualStudio solution for download. Feel free to use it in your own projects.

If you find a bug, have any improvements or feel like discussing this in more depth, feel free to post a comment.

 

 

2 thoughts on “IsInstanceOfTypeFamily – Check whether a given type is a member of a “type family”

Leave a Reply

Your email address will not be published. Required fields are marked *