Determining if an Open Generic Type IsAssignableFrom a Type

This article was originally published in my blog (affectionately referred to as blargh) on . The original blog no longer exists as I've migrated everything to this wiki.

The original URL of this post was at https://tmont.com/blargh/2011/3/determining-if-an-open-generic-type-isassignablefrom-a-type. Hopefully that link redirects back to this page.

It may come to pass in your dirty .NET dealings that you need to do something like this:

C♯
public void DoTheAwesome(Type type) {
  if (!typeof(IEnumerable<>).IsAssignableFrom(type)) {
    return;
  }

  // do awesome stuff
}

If you're asking why you might need to ever do something like this, you clearly haven't worked with enough Inversion of Control frameworks.

The point is that the above conditional is always false no matter the value of type. I need it to be true basically if type implements IEnumerable<T>, only it wasn't just IEnumerable<T> and type could be anything.

So a bit of googling and fast-and-furious copypasting from StackOverflow yielded something that worked but not quite (basically the open generic part didn't work, which what I really wanted). But I was able to wrangle it into something that suited my needs. The original code is here.

C♯
public static class AssignableExtensions {
  /// <summary>
  /// Determines whether the <paramref name="genericType"/> is assignable from
  /// <paramref name="givenType"/> taking into account generic definitions
  /// </summary>
  public static bool IsAssignableToGenericType(this Type givenType, Type genericType) {
    if (givenType == null || genericType == null) {
      return false;
    }

    return givenType == genericType 
      || givenType.MapsToGenericTypeDefinition(genericType) 
      || givenType.HasInterfaceThatMapsToGenericTypeDefinition(genericType) 
      || givenType.BaseType.IsAssignableToGenericType(genericType);
  }

  private static bool HasInterfaceThatMapsToGenericTypeDefinition(this Type givenType, Type genericType) {
    return givenType
      .GetInterfaces()
      .Where(it => it.IsGenericType)
      .Any(it => it.GetGenericTypeDefinition() == genericType);
  }

  private static bool MapsToGenericTypeDefinition(this Type givenType, Type genericType) {
    return genericType.IsGenericTypeDefinition
      && givenType.IsGenericType
      && givenType.GetGenericTypeDefinition() == genericType;
  }
}

And here are some tests to verify that it might be doing what you think it might or might not be doing:

C♯
[TestFixture]
public class AssignableTests {
  [Test]
  public void Should_be_assignable_from_open_generic_type_to_concrete_open_generic_type() {
    Assert.That(typeof(Foo<>).IsAssignableToGenericType(typeof(IFoo<>)));
  }

  [Test]
  public void Should_be_assignable_from_open_generic_type_to_generic_interface_type() {
    Assert.That(typeof(IFoo<int>).IsAssignableToGenericType(typeof(IFoo<>)));
  }

  [Test]
  public void Should_be_assignable_from_open_generic_type_to_itself() {
    Assert.That(typeof(IFoo<>).IsAssignableToGenericType(typeof(IFoo<>)));
  }

  [Test]
  public void Should_be_assignable_from_open_generic_type_to_concrete_generic_type() {
    Assert.That(typeof(Foo<int>).IsAssignableToGenericType(typeof(IFoo<>)));
  }

  [Test]
  public void Should_be_assignable_from_open_generic_type_to_nongeneric_concrete_type() {
    Assert.That(typeof(Bar).IsAssignableToGenericType(typeof(IFoo<>)));
  }

  public interface IFoo<T> {}
  public class Foo<T> : IFoo<T> { }
  public class Bar : IFoo<int> { }
}

This code is licensed under Creative Commons (same as StackOverflow) so feel free to go to town.