0

As I google, I am running across answers on how to get all derived types of a generic class. But what I really want is just all the variations of a generic class.

The problem is that we are logging too much info in higher environments. We use Serilog, and I want to use the MinimumLevel.Overide() method to control logging based on environment.

In order to do this, I need to specify the logging source. Because there are a lot of types in the application and more will certainly be added, I'd like to use reflection to find every class of ILogger<whatever>.

5
  • 2
    For one, 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 with ILogger<T> in your code. Is that correct? Commented Jul 25, 2024 at 6:03
  • 1
    This question is similar to: .NET - Getting all implementations of a generic interface?. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Jul 25, 2024 at 6:05
  • 3
    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 find ILogger<T> arguments. Commented Jul 25, 2024 at 7:01
  • @ProgrammingLlama Yes, you are correct. Commented Jul 27, 2024 at 5:28
  • I'd suggest doing a RegEx search of ILogger<.*?> and perhaps also CreateLogger<.*?> Commented Jul 30, 2024 at 1:37

1 Answer 1

0

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<>)); 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.