Last active
June 29, 2021 10:05
-
-
Save xoofx/710aaf86e0e8c81649d1261b1ef9590e to your computer and use it in GitHub Desktop.
Gets the list of the generic type instances used in an assembly
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class AssemblyHelper | |
{ | |
/// <summary> | |
/// Gets the list of concrete generic type instances used in an assembly. | |
/// See remarks | |
/// </summary> | |
/// <param name="assembly">The assembly</param> | |
/// <returns>The list of generic type instances</returns> | |
/// <remarks> | |
/// Note that this method is fetching only direct type instances (through type, method argument or fields) | |
/// </remarks> | |
public static List<Type> GetGenericTypeInstances(System.Reflection.Assembly assembly) | |
{ | |
var types = new List<Type>(); | |
var visited = new HashSet<Type>(); | |
CollectGenericTypeInstances(assembly, types, visited); | |
return types; | |
} | |
private static void CollectGenericTypeInstances(System.Reflection.Assembly assembly, List<Type> types, HashSet<Type> visited) | |
{ | |
// From: https://gist.github.com/xoofx/710aaf86e0e8c81649d1261b1ef9590e | |
if (assembly == null) throw new ArgumentNullException(nameof(assembly)); | |
const int mdMaxCount = 1 << 24; | |
foreach (var module in assembly.Modules) | |
{ | |
for (int i = 1; i < mdMaxCount; i++) | |
{ | |
try | |
{ | |
// Token base id for TypeSpec | |
const int mdTypeSpec = 0x1B000000; | |
var type = module.ResolveType(mdTypeSpec | i); | |
if (type.IsConstructedGenericType && !type.ContainsGenericParameters) | |
{ | |
CollectGenericTypeInstances(type, types, visited); | |
} | |
} | |
catch (ArgumentOutOfRangeException) | |
{ | |
break; | |
} | |
catch (ArgumentException) | |
{ | |
// Can happen on ResolveType on certain generic types, so we continue | |
} | |
} | |
for (int i = 1; i < mdMaxCount; i++) | |
{ | |
try | |
{ | |
// Token base id for MethodSpec | |
const int mdMethodSpec = 0x2B000000; | |
var method = module.ResolveMethod(mdMethodSpec | i); | |
var genericArgs = method.GetGenericArguments(); | |
foreach (var genArgType in genericArgs) | |
{ | |
if (genArgType.IsConstructedGenericType && !genArgType.ContainsGenericParameters) | |
{ | |
CollectGenericTypeInstances(genArgType, types, visited); | |
} | |
} | |
} | |
catch (ArgumentOutOfRangeException) | |
{ | |
break; | |
} | |
catch (ArgumentException) | |
{ | |
// Can happen on ResolveType on certain generic types, so we continue | |
} | |
} | |
for (int i = 1; i < mdMaxCount; i++) | |
{ | |
try | |
{ | |
// Token base id for Field | |
const int mdField = 0x04000000; | |
var field = module.ResolveField(mdField | i); | |
CollectGenericTypeInstances(field.FieldType, types, visited); | |
} | |
catch (ArgumentOutOfRangeException) | |
{ | |
break; | |
} | |
catch (ArgumentException) | |
{ | |
// Can happen on ResolveType on certain generic types, so we continue | |
} | |
} | |
// Scan for types used in constructor arguments to assembly-level attributes | |
foreach (var customAttribute in assembly.CustomAttributes) | |
{ | |
foreach (var argument in customAttribute.ConstructorArguments) | |
{ | |
if (argument.ArgumentType == typeof(Type)) | |
{ | |
CollectGenericTypeInstances((Type)argument.Value, types, visited, typeFilter); | |
} | |
} | |
} | |
} | |
} | |
private static void CollectGenericTypeInstances(Type type, List<Type> types, HashSet<Type> visited) | |
{ | |
if (type.IsPrimitive) return; | |
if (!visited.Add(type)) return; | |
// Add only concrete types | |
if (type.IsConstructedGenericType && !type.ContainsGenericParameters) | |
{ | |
types.Add(type); | |
} | |
// Collect recursively generic type arguments | |
var genericTypeArguments = type.GenericTypeArguments; | |
foreach (var genericTypeArgument in genericTypeArguments) | |
{ | |
if (!genericTypeArgument.IsPrimitive) | |
{ | |
CollectGenericTypeInstances(genericTypeArgument, types, visited); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment