我在使用 log4net 时遇到了一些奇怪的行为,想知道是否有人可以向我解释这一点,我很想了解更多信息来理解它。
在我的 WPF App.xaml.cs OnStartup 覆盖方法中,我有以下代码设置用于日志记录的 log4net 属性:
// logLocation is a path to a subdir in the users' appdata roaming dir
log4net.GlobalContext.Properties["LogLocation"] = logLocation;
logger = LogManager.GetLogger(typeof(App));
logger.Info("OnStartup: " + string.Join(" ", e.Args));
在创建任何其他记录器之前我会这样做(或者我是这么认为的)。
在我的配置文件中,我有以下行:
<file type="log4net.Util.PatternString" value="%property{LogLocation}" />
这可以指定日志文件的位置。但是,我遇到了失败的情况 - 导致记录写入执行目录中的文件名“(null)”。
造成这种情况的原因似乎是下面的伪代码,它在上面代码之后的同一个 OnStartup 方法中:
AnyClass ac = new AnyClass();
ac.NoOp();
其中 AnyClass 有一个像这样实例化的记录器:
private static ILog logger = LogManager.GetLogger(typeof(AnyClass));
我使用伪代码的原因是我可以用我实例化的任何类复制这种行为并调用一个方法。如果未调用任何方法,则日志记录路径按预期工作。
有几点需要注意:
- 当我在调试器中以调试或发布模式运行它时,这有效。仅当我直接运行 exe 或通过“不调试启动”时才会出现该错误。
- 如果记录器不是静态定义的——那么问题就消失了
如果我向 AnyClass 添加一个静态构造函数,那么问题就会消失,即:
静态 AnyClass() {}
如果我将对 ac.NoOp() 的调用移至由 OnStartup 调用的辅助方法 - 错误就会消失。
因此,回顾一下,错误只是由使用静态记录器初始化的类实例化,并在 OnStartup 方法中调用该类的方法引起的。
我有几种方法可以解决这个问题,但我很想了解更多以了解为什么会发生这种情况。