in src/Microsoft.Azure.WebJobs.Host/Bindings/PatternMatcher.cs [207:270]
internal static Type ResolveGenerics(Type type, Dictionary<string, Type> genericArgs)
{
// A generic type definition is an actual class / interface declaration,
// not to be confused with a signature referenced by the definition.
// Here, Foo'1 is the generic type definition, with one generic parameter, named 'T'
// IEnumerable<T> is a type signature that containes a generic parameter.
// T is the generic parameter.
// class Foo<T> : IEnumerable<T>
//
// MakeGenericType can only be called on a GenericTypeDefinition.
if (type.IsGenericTypeDefinition)
{
var typeArgs = type.GetGenericArguments();
int len = typeArgs.Length;
var actualTypeArgs = new Type[len];
for (int i = 0; i < len; i++)
{
actualTypeArgs[i] = genericArgs[typeArgs[i].Name];
}
var resolvedType = type.MakeGenericType(actualTypeArgs);
return resolvedType;
}
else
{
// Simple case: T
if (type.IsGenericParameter)
{
var actual = genericArgs[type.Name];
return actual;
}
else if (type.ContainsGenericParameters)
{
if (type.IsArray)
{
// T[]
var elementType = type.GetElementType();
var resolved = ResolveGenerics(elementType, genericArgs);
return resolved.MakeArrayType();
}
// eg, IEnumerable<T>, IConverter<int, T>
// Must decompose to the generic definition, resolve each arg, and build back up.
// potentially recursive case: ie, IConverter<int, T>
var def = type.GetGenericTypeDefinition();
var args = type.GetGenericArguments();
var resolvedArgs = new Type[args.Length];
for (int i = 0; i < args.Length; i++)
{
resolvedArgs[i] = ResolveGenerics(args[i], genericArgs);
}
var finalType = def.MakeGenericType(resolvedArgs);
return finalType;
}
else
{
// Easy non-generic case. ie: string, int
return type;
}
}
}