我有以下代码(从实际代码中提取)
public static class AssemblyLogger {
public static Lazy<Window> Window { get; } = new Lazy<Window>(NewWindowHandler);
public static IScheduler Scheduler =>
new DispatcherScheduler( Window.Value.Dispatcher );
}
当我调用Scheduler时,我得到一个NullReferenceException.我看到调试器停止了
据我所知,这应该是不可能的.窗口是静态初始化和只读的,因此任何对它的进一步访问应该只是get,它永远不应该为null.
我已经设置了一个针对初始化器的断点,但它永远不会被击中
我也尝试过静态只读字段,但仍然存在同样的问题
public static readonly Lazy<Window> Window = new Lazy<Window>(NewWindowHandler);
是否可能对静态初始化有竞争条件?
到目前为止尝试制作MCVE并不成功.以下规范测试我的最小可用代码和真实代码. MCVE通过:(而真正的一个失败.我错过了一些背景,需要进一步的工作来隔离问题.
public class Tester
{
public static class AssemblyLoggerMCVE
{
public static Lazy<Window> Window { get; } = new Lazy<Window>(NewWindowHandler);
private static Window NewWindowHandler() => new Window();
public static IScheduler Scheduler =>
new DispatcherScheduler(Window.Value.Dispatcher);
}
/// This passes
[StaFact]
public void AssemblyLoggerMCVEShouldWork()
{
AssemblyLoggerMCVE.Scheduler.Should().NotBeNull();
}
/// This fails
[StaFact]
public void AssemblyLoggerShouldWork()
{
AssemblyLogger.Scheduler.Should().NotBeNull();
}
}
最佳答案 错误可以通过以下测试用例清楚地复制,该测试用例具有比所建议的问题更多的上下文.
public class Tester
{
public class AssemblyLoggerControlModel
{
public static IScheduler S = AssemblyLoggerMCVE.Scheduler;
}
public class AssemblyLogger
{
public static AssemblyLoggerControlModel ModelInstance { get; } =
new AssemblyLoggerControlModel();
public static readonly Lazy<Window> Window =
new Lazy<Window>(NewWindowHandler);
private static Window NewWindowHandler() => new Window();
public static IScheduler Scheduler =>
new DispatcherScheduler(Window.Value.Dispatcher);
}
}
静态初始化器之间存在循环依赖关系.静态属性的静态初始化AssemblyLogger.ModelInstance导致静态属性AssemblyLoggerControlModel.S被初始化,然后尝试调用静态AssemblyLogger.Scheduler方法,该方法又试图访问Window,因为AssemblyLogger的静态初始化未完成仍为空.
基本上我的代码是纯粹的邪恶,最好的办法是