How to determine generic implementers and type parameters at runtime
Share
Recently I needed an easy way to figure out whether an instance or type implements a given interface, whether or not that interface is generic, as well as obtain the generic arguments (the real types the instance uses in place of a generic type) for that interface.
So I’ve written a small set of extension methods to give you these features. There are only two methods, but they are available with multiple signatures. The first method allows you to determine if an instance implements any interface, whether it is generic or non-generic.
// A regular, non-generic interface var result = instance.Implements(typeof(INoDeclaredTypes)); // A generic interface without a type; true for any type implemented var result = instance.Implements(typeof(ISingleDeclaredType<>)); // A generic interface with a specific type; truly only for this type var result = instance.Implements(typeof(ISingleDeclaredType<double>));
The second method determines the actual parameters declared in any implemented interfaces for an instance.
// Assumes that your instance only implements one of these interfaces var result = instance.GetDeclaredTypeForGeneric(typeof(ISingleDeclaredType<>)); // Will return all declared types for all implementations var results = instance.GetDeclaredTypesForGeneric(typeof(ISingleDeclaredType<>)); // Will return all declared types in any implementations var results = instance.GetDeclaredTypesForGeneric(typeof(IMultipleDeclaredTypes<,>));
I’ve found these extension methods useful for code that needs to inspect an instance for a given interface and create new instances of the types declared within them to do work, and hope you’ll find use for them as well.
using System;
using System.Collections.Generic;
public static class InterfaceExtensions
{
public static bool Implements(this object instance, Type interfaceType)
{
return interfaceType.IsGenericTypeDefinition
? instance.ImplementsGeneric(interfaceType)
: interfaceType.IsAssignableFrom(instance.GetType());
}
public static bool Implements<T>(this object instance)
{
var interfaceType = typeof(T);
return instance.Implements(interfaceType);
}
public static bool Implements<T>(this object instance, T interfaceType)
{
return instance.Implements<T>();
}
public static bool Implements<T>(this Type type, T interfaceType)
{
return Implements<T>(type);
}
public static bool Implements<T>(this Type type)
{
var interfaceType = typeof(T);
return interfaceType.IsGenericTypeDefinition
? type.ImplementsGeneric(interfaceType)
: interfaceType.IsAssignableFrom(type);
}
public static Type GetDeclaredTypeForGeneric(this object instance, Type interfaceType)
{
return instance.GetType().GetDeclaredTypeForGeneric(interfaceType);
}
public static Type GetDeclaredTypeForGeneric<T>(this object instance)
{
var interfaceType = typeof(T);
return instance.GetDeclaredTypeForGeneric(interfaceType);
}
public static Type GetDeclaredTypeForGeneric<T>(this object instance, T interfaceType)
{
return instance.GetDeclaredTypeForGeneric(typeof(T));
}
public static Type GetDeclaredTypeForGeneric<T>(this Type type)
{
var interfaceType = typeof(T);
return type.GetDeclaredTypeForGeneric(interfaceType);
}
public static Type GetDeclaredTypeForGeneric<T>(this Type type, T interfaceType)
{
return type.GetDeclaredTypeForGeneric(typeof(T));
}
public static Type GetDeclaredTypeForGeneric(this Type baseType, Type interfaceType)
{
var type = default(Type);
if (baseType.ImplementsGeneric(interfaceType))
{
var generic = baseType.GetInterface(interfaceType.FullName);
if (generic.IsGenericType)
{
var args = generic.GetGenericArguments();
if (args.Length == 1)
{
type = args[0];
}
}
}
return type;
}
public static IEnumerable<Type> GetDeclaredTypesForGeneric(this object instance, Type interfaceType)
{
return instance.GetType().GetDeclaredTypesForGeneric(interfaceType);
}
public static IEnumerable<Type> GetDeclaredTypesForGeneric<T>(this object instance)
{
var interfaceType = typeof(T);
return instance.GetType().GetDeclaredTypesForGeneric(interfaceType);
}
public static IEnumerable<Type> GetDeclaredTypesForGeneric<T>(this object instance, T interfaceType)
{
return instance.GetDeclaredTypesForGeneric<T>();
}
public static IEnumerable<Type> GetDeclaredTypesForGeneric<T>(this Type type)
{
var interfaceType = typeof(T);
return type.GetDeclaredTypesForGeneric(interfaceType);
}
public static IEnumerable<Type> GetDeclaredTypesForGeneric<T>(this Type type, T interfaceType)
{
return type.GetDeclaredTypesForGeneric(typeof(T));
}
public static IEnumerable<Type> GetDeclaredTypesForGeneric(this Type type, Type interfaceType)
{
foreach (var generic in type.GetGenericInterfacesFor(interfaceType))
{
foreach (var arg in generic.GetGenericArguments())
{
yield return arg;
}
}
}
private static IEnumerable<Type> GetGenericInterfacesFor(this Type type, Type interfaceType)
{
var candidates = type.GetInterfaces();
foreach (var candidate in candidates)
{
if(!candidate.IsGenericType)
{
continue;
}
var definition = candidate.GetGenericTypeDefinition();
if (definition == interfaceType)
{
yield return candidate;
}
}
}
private static bool ImplementsGeneric(this Type type, Type targetType)
{
var interfaceTypes = type.GetInterfaces();
foreach (var interfaceType in interfaceTypes)
{
if (!interfaceType.IsGenericType)
{
continue;
}
if (interfaceType.GetGenericTypeDefinition() == targetType)
{
return true;
}
}
var baseType = type.BaseType;
if (baseType == null)
{
return false;
}
return baseType.IsGenericType
? baseType.GetGenericTypeDefinition() == targetType
: baseType.ImplementsGeneric(targetType);
}
private static bool ImplementsGeneric(this object instance, Type targetType)
{
return instance.GetType().ImplementsGeneric(targetType);
}
}
Socialized