关闭线程窗体时的NullReferenceException

本文关键字:NullReferenceException 窗体 线程 | 更新日期: 2023-09-27 18:04:55

上下文:

我创建了一个Windows窗体应用程序,它在启动前运行启动屏幕。快速地,这里是包含我的Program.cs:

public static Thread splashScreenThread = null;
public static FormSplashScreen formSplashScreen;
[STAThread]
static void Main(string[] args) {
    // Show splash screen
    splashScreenThread = new Thread(new ThreadStart(ShowSplashScreen));
    splashScreenThread.IsBackground = true;
    splashScreenThread.Start();
    // Load some components in background
    LoadComponentsInBackground()
    // Hide the splash screen
    if (splashScreenThread != null) {
        formSplashScreen.Invoke(new MethodInvoker(delegate {
            formSplashScreen.Close();
            formSplashScreen.Dispose();
        }));
        splashScreenThread = null;
    }
    // Start now the application
    Application.Run();
}
private static void ShowSplashScreen() {
    formSplashScreen = new FormSplashScreen();
    formSplashScreen.ShowDialog();
}

问题:

我的问题并不是每次我启动应用程序时都发生,它似乎是随机的,在某些pc上更经常发生,而在其他pc上更少…所以我有点困惑,而且我真的不明白它是从哪里来的:

NullReferenceExceptionformSplashScreen.Invoke(...Close...)行上被抛出,但formSplashScreen被正确初始化(我在调试时检查了它)。
我不确定这是来自线程还是来自另一个点…

可能的解决方案:

我也许可以用下面这样的东西把引起问题的行括起来,但这只是绕过问题,我宁愿理解它并正确解决它。

while (splashScreenThread != null) {
    try {
        formSplashScreen.Invoke(new MethodInvoker(delegate {
            formSplashScreen.Close();
            formSplashScreen.Dispose();
        }));
        splashScreenThread = null;
    } catch (Exception e) {
    }
}

关闭线程窗体时的NullReferenceException

这是一个竞态条件,因为线程已经创建并启动,但是SplashScreen还没有创建。

换句话说,你试图在启动屏幕创建之前关闭它。

你可以使用EventWaitHandle来确保SplashScreen已经被创建,或者至少等到它不为空。

另一个选择是向屏幕发出关闭的信号,让他处理关闭逻辑。