关于.NET 10中CA1873警告的日志优化实现思路疑问
兄弟,我太懂你这种烦躁了——本来写日志就是图个轻量方便,结果突然冒出来CA1873警告,还要手动给每处日志套个if (_logger.IsEnabled(...))的判断,想想都头大。
先给你掰扯清楚官方为啥没搞你说的那种Lazy重载,再给你俩实际可用的解决方案,你自己选:
为啥官方没做Lazy参数的日志重载?
其实官方不是没想到,而是他们更推荐性能更优、规范度更高的结构化日志方案,而不是通过新增API来“妥协”。主要有两个原因:
已有更高效的替代方案:官方主推的
LoggerMessage.Define模式,本身就自带延迟计算+编译时优化,比你写的运行时Func委托性能好得多。它会在编译阶段生成强类型的日志委托,自动帮你做IsEnabled判断,完全不需要手动加if。比如:// 提前定义好日志模板(一般放类的静态字段里) private static readonly Action<ILogger, int, Exception?> _logMessageCount = LoggerMessage.Define<int>( LogLevel.Information, new EventId(1, "MessageCount"), "My message:{MessageCount}."); // 调用的时候直接传参数就行,自动处理判断 _logMessageCount(_logger, messages.Count, null);这种方式不仅没有额外的运行时开销,还能保证日志的结构化一致性,是官方最推荐的生产级方案。
API复杂度控制:如果给每个日志级别都加一套Lazy重载,会让
ILogger的API变得异常臃肿,而且不同开发者可能会混用普通Log和LazyLog,反而增加代码的维护成本。官方更倾向于引导开发者用标准方案,而不是提供过多的“捷径”API。
不想加if判断?给你两个可行的路子
路子一:自己封装Lazy扩展(适合快速改造现有代码)
你想的那个扩展方案完全可行!甚至可以优化得更顺手一点,比如支持可变参数的Func<object>,不用手动创建数组:
public static class LoggerLazyExtensions { public static void LogInformationLazy(this ILogger logger, string message, params Func<object>[] parameterFactories) { if (!logger.IsEnabled(LogLevel.Information)) return; var parameters = parameterFactories.Select(f => f()).ToArray(); logger.LogInformation(message, parameters); } // 同理可以给其他日志级别(Debug/Warning/Error等)都加上对应的扩展 public static void LogDebugLazy(this ILogger logger, string message, params Func<object>[] parameterFactories) { if (!logger.IsEnabled(LogLevel.Debug)) return; var parameters = parameterFactories.Select(f => f()).ToArray(); logger.LogDebug(message, parameters); } } // 调用的时候直接写: _logger.LogInformationLazy("My message:{MessageCount}.", () => messages.Count);
这个方案几乎不需要改现有日志的写法,只是把LogInformation换成LogInformationLazy,完美解决CA1873警告,还不用加if判断。
路子二:改用LoggerMessage(适合新项目或重构项目)
如果是新项目或者有时间重构老代码,强烈建议用官方的LoggerMessage模式,性能拉满还规范。除了上面的例子,还可以用LoggerMessage.DefineScope处理日志上下文,功能更完整。
最后总结
- 官方没加Lazy重载是因为有更高效的标准方案,不是没想到
- 你自己封装Lazy扩展完全没问题,是快速解决问题的好办法
- 追求性能和规范的话,选LoggerMessage准没错
说白了就是看你项目的情况:如果是老项目不想大改,自己封装扩展;如果是新项目或者要优化性能,就上LoggerMessage。怎么舒服怎么来就行!




