如何在ILogger<TCategoryName>的类别名中包含泛型参数类型名
解决ILogger泛型类别名显示泛型参数的问题
默认情况下,使用ILogger<Foo<string>>时,日志输出的类别名是Foo[0],这是因为.NET默认会把泛型类型的名称(如Foo1)格式化为Foo[0]。要让类别名显示具体的泛型参数类型(如Foo[System.String]),可以通过以下两种方式实现:
方法一:手动指定类别名创建Logger
直接通过ILoggerFactory创建Logger时,传入解析后的泛型类型名称:
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; class Foo<T> { } // 解析泛型类型名称的工具方法 public static string GetGenericTypeName(Type type) { if (!type.IsGenericType) return type.FullName ?? type.Name; var genericArgs = string.Join(", ", type.GetGenericArguments().Select(GetGenericTypeName)); return $"{type.Name.Split('`')[0]}[{genericArgs}]"; } using var services = new ServiceCollection() .AddLogging(options => options.AddConsole()) .BuildServiceProvider(); var loggerFactory = services.GetRequiredService<ILoggerFactory>(); // 手动生成正确的类别名 var logger = loggerFactory.CreateLogger(GetGenericTypeName(typeof(Foo<string>))); logger.LogInformation("test"); // 输出:info: Foo[System.String]
方法二:通过DI注册自定义泛型Logger(自动处理)
如果希望通过DI获取ILogger<T>时自动使用正确的类别名,可以自定义一个泛型Logger实现,替换默认的ILogger<T>注册:
1. 实现自定义泛型Logger
public class GenericAwareLogger<T> : ILogger<T> { private readonly ILogger _innerLogger; public GenericAwareLogger(ILoggerFactory loggerFactory) { var categoryName = GetGenericTypeName(typeof(T)); _innerLogger = loggerFactory.CreateLogger(categoryName); } public IDisposable BeginScope<TState>(TState state) => _innerLogger.BeginScope(state); public bool IsEnabled(LogLevel logLevel) => _innerLogger.IsEnabled(logLevel); public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) { _innerLogger.Log(logLevel, eventId, state, exception, formatter); } // 递归解析泛型类型名称 private static string GetGenericTypeName(Type type) { if (!type.IsGenericType) return type.FullName ?? type.Name; var genericArgs = string.Join(", ", type.GetGenericArguments().Select(t => t.FullName ?? t.Name)); return $"{type.Name.Split('`')[0]}[{genericArgs}]"; } }
2. 注册到DI容器
using var services = new ServiceCollection() .AddLogging(options => options.AddConsole()) // 替换默认的ILogger<T>实现 .AddSingleton(typeof(ILogger<>), typeof(GenericAwareLogger<>)) .BuildServiceProvider(); // 直接获取ILogger<Foo<string>>,自动使用正确的类别名 var logger = services.GetRequiredService<ILogger<Foo<string>>>(); logger.LogInformation("test"); // 输出:info: Foo[System.String]
可选优化:简化类型名称
如果不想显示完整的System.String,而是用string这种友好名称,可以修改GetGenericTypeName方法,添加常用类型的映射处理:
private static string GetFriendlyTypeName(Type type) { var typeMap = new Dictionary<Type, string> { { typeof(string), "string" }, { typeof(int), "int" }, { typeof(bool), "bool" }, // 可添加更多常用类型 }; if (typeMap.TryGetValue(type, out var friendlyName)) return friendlyName; if (!type.IsGenericType) return type.Name; var genericArgs = string.Join(", ", type.GetGenericArguments().Select(GetFriendlyTypeName)); return $"{type.Name.Split('`')[0]}[{genericArgs}]"; }
替换后,Foo<string>会显示为Foo[string],格式更简洁。
内容的提问来源于stack exchange,提问作者Liero
相关产品推荐
相关产品推荐

