First of all, all your ILogger<whatever> interfaces are statically known to the assembly you want to reflect and are contained in its metadata. You don't know the exact types, you have to traverse all the assembly types, including nested ones. Most likely, you want to retrieve the classes from all the assemblies loaded.
Let's start with the library types we need to use:
using Type = System.Type; using TypeList = System.Collections.Generic.List<System.Type>; using Assembly = System.Reflection.Assembly; using AppDomain = System.AppDomain;
Now, for the illustration, let's define ILogger and some implementing classes somewhere:
internal interface ILogger<TYPE> { //... } internal class StringLogger : ILogger<string> { //... } internal class TimeLogger : ILogger<System.DateTime> { //... } internal class AssemblyLogger : ILogger<System.Reflection.Assembly> { //... }
In your real code, you will need to use the real ILogger generic interface, but you will have no information on the implementing classes. Let's retrieve them:
static class LoggerClassifier { static void GetLoggerClasses(Assembly assembly, TypeList collection) { static void ProcessClass(Type type, Type loggerType, TypeList collection) { Type[] interfaces = type.GetInterfaces(); foreach (var interfaceInstance in interfaces) { if (!interfaceInstance.IsGenericType) continue; if (loggerType == interfaceInstance.GetGenericTypeDefinition()) collection.Add(type); } //loop } //ProcessClass Type loggerType = typeof(ILogger<>); Type[] assemblyTypes = assembly.GetTypes(); foreach (var type in assemblyTypes) { ProcessClass(type, loggerType, collection); Type[] nestedClasses = type.GetNestedTypes(); foreach (var nestedClass in nestedClasses) ProcessClass(nestedClass, loggerType, collection); } //loop } //GetLoggerClasses internal static Type[] GetLoggerClasses() { TypeList collection = new(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in assemblies) GetLoggerClasses(assembly, collection); return collection.ToArray(); } //GetLoggerClasses //... } //class LoggerClassifier
Please note one important and universal thing: you cannot really reliably use the name of Ilogger<> to pass to Type.GetInterface, not even via nameof. Not only the entire idea of using strings representing data instead of data is bad but in the case of the generic types their names are mangled, and the standard doesn't guarantee exact naming rules. Generally, string representation of types doesn't really fully guarantee the type identity, but typeof does guarantee it.
Let's test it:
Type[] loggerTypes = LoggerClassifier.GetLoggerClasses();
Examine loggerTypes, and you will find three classes found in your current application domain, StringLogger, TimeLogger, and AssemblyLogger. Anyway, whatever generic parameters you have applied to ILogger<>…
Now when we have found the algorithm for ILogger, we can abstract it out to cover different interfaces:
static class ImplementationClassifier { static void GetImplementingClasses(Type interfaceType, Assembly assembly, TypeList collection) { static void ProcessClass(Type type, Type loggerType, TypeList collection) { Type[] interfaces = type.GetInterfaces(); foreach (var interfaceInstance in interfaces) { if (!interfaceInstance.IsGenericType) continue; if (loggerType == interfaceInstance.GetGenericTypeDefinition()) collection.Add(type); } //loop } //ProcessClass Type[] assemblyTypes = assembly.GetTypes(); foreach (var type in assemblyTypes) { ProcessClass(type, interfaceType, collection); Type[] nestedClasses = type.GetNestedTypes(); foreach (var nestedClass in nestedClasses) ProcessClass(nestedClass, interfaceType, collection); } //loop } //GetImplementingClasses internal static Type[] GetImplementingClasses(Type interfaceType) { TypeList collection = new(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in assemblies) GetImplementingClasses(interfaceType, assembly, collection); return collection.ToArray(); } //GetImplementingClasses //... } //class ImplementationClassifier
Even though the usage is less obvious, let's test it:
var anotherDemo = ImplementationClassifier.GetImplementingClasses( typeof(ILogger<>));
ILogger<T>is a generic interface, not a generic class, so you would want to find all concrete implementations of that interface. From the other parts of your question, I'm not convinced that this is actually what you want. It sounds like you want to find all values of T (the generic arguments) used withILogger<T>in your code. Is that correct?ILogger<T>is defined as an open generic service in DI. I'm not sure there's an easy answer to this question, you'd probably need to scan the constructors of all your services to findILogger<T>arguments.ILogger<.*?>and perhaps alsoCreateLogger<.*?>