private static IDictionary<string, TypeReference> GetGenericArgsMap(TypeReference type, IDictionary<string, TypeReference> superTypeMap,
IList<TypeReference> mappedFromSuperType)
{
var result = new Dictionary<string, TypeReference>();
if (type is GenericInstanceType == false)
{
return result;
}
var genericArgs = ((GenericInstanceType)type).GenericArguments;
var genericPars = ((GenericInstanceType)type).ElementType.Resolve().GenericParameters;
/*
* Now genericArgs contain concrete arguments for the generic
* parameters (genericPars).
*
* However, these concrete arguments don't necessarily have
* to be concrete TypeReferences, these may be referencec to
* generic parameters from super type.
*
* Example:
*
* Consider following hierarchy:
* StringMap<T> : Dictionary<string, T>
*
* StringIntMap : StringMap<int>
*
* What would happen if we walk up the hierarchy from StringIntMap:
* -> StringIntMap
* - here dont have any generic agrs or params for StringIntMap.
* - but when we reesolve StringIntMap we get a
* reference to the base class StringMap<int>,
* -> StringMap<int>
* - this reference will have one generic argument
* System.Int32 and it's ElementType,
* which is StringMap<T>, has one generic argument 'T'.
* - therefore we need to remember mapping T to System.Int32
* - when we resolve this class we'll get StringMap<T> and it's base
* will be reference to Dictionary<string, T>
* -> Dictionary<string, T>
* - now *genericArgs* will be System.String and 'T'
* - genericPars will be TKey and TValue from Dictionary
* declaration Dictionary<TKey, TValue>
* - we know that TKey is System.String and...
* - because we have remembered a mapping from T to
* System.Int32 and now we see a mapping from TValue to T,
* we know that TValue is System.Int32, which bring us to
* conclusion that StringIntMap is instance of
* -> Dictionary<string, int>
*/
for (int i = 0; i < genericArgs.Count; i++)
{
var arg = genericArgs[i];
var param = genericPars[i];
if (arg is GenericParameter)
{
TypeReference mapping;
if (superTypeMap.TryGetValue(arg.Name, out mapping))
{
mappedFromSuperType.Add(mapping);
result.Add(param.Name, mapping);
}
//else
//{
// throw new Exception(string.Format(
//"GetGenericArgsMap: A mapping from supertype was not found. " +
//"Program searched for generic argument of name {0} in supertype generic arguments map " +
//"as it should server as value form generic argument for generic parameter {1} in the type {2}",
//arg.Name,
//param.Name,
//type.FullName));
//}
}
else
{
result.Add(param.Name, arg);
}
}
return result;
}
}