Determining if an Open Generic Type IsAssignableFrom a Type[source]

xml
<glacius:metadata>
    <title>Determining if an Open Generic Type IsAssignableFrom a Type</title>
    <description>How to determine if an open generic type IsAssignableFrom a Type in .NET circa 2011</description>
    <category>Programming</category>
    <category>Legacy blog posts</category>
    <category>C#</category>
</glacius:metadata>
<glacius:macro name="legacy blargh banner">
    <properties>
        <originalUrl>https://tmont.com/blargh/2011/3/determining-if-an-open-generic-type-isassignablefrom-a-type</originalUrl>
        <originalDate>2011-03-14T04:04:21.000Z</originalDate>
    </properties>
</glacius:macro>
<p>It may come to pass in your dirty .NET dealings that you need to do something like this:</p>
<glacius:code lang="csharp"><![CDATA[public void DoTheAwesome(Type type) {
  if (!typeof(IEnumerable<>).IsAssignableFrom(type)) {
    return;
  }
  // do awesome stuff
}]]></glacius:code>
<p>
  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.
</p>
<p>
  The point is that the above conditional is always <code>false</code> no matter the value
  of <code>type</code>. I need it to be <code>true</code> basically if <code>type</code> 
  implements <code>IEnumerable&lt;T&gt;</code>, only it wasn't just <code>IEnumerable&lt;T&gt;</code> 
  and <code>type</code> could be anything.
</p>
<p>
  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 <a href="https://stackoverflow.com/a/75502">here</a>.
</p>
<glacius:code lang="csharp"><![CDATA[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;
  }
}]]></glacius:code>
<p>
  And here are some tests to verify that it might be doing what you think it might 
  or might not be doing:
</p>
<glacius:code lang="csharp"><![CDATA[[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> { }
}]]></glacius:code>
<p>
  This code is licensed under 
  <a href="https://creativecommons.org/licenses/by-sa/3.0/">Creative Commons</a>
  (same as StackOverflow) so feel free to go to town.
</p>