C# 触发事件时出现NullReferenceException

C# 触发事件时出现NullReferenceException,c#,.net,events,nullreferenceexception,C#,.net,Events,Nullreferenceexception,我有这段代码,但至少对我来说,这会导致一个奇怪的异常 public class Flight { public class MessageEventArgs : System.EventArgs { public string msgContent; } public event System.EventHandler LogMessage; public void StartFlight() { string

我有这段代码,但至少对我来说,这会导致一个奇怪的异常

public class Flight
{
    public class MessageEventArgs : System.EventArgs
    {
        public string msgContent;
    }

    public event System.EventHandler LogMessage;

    public void StartFlight()
    {
        string tmpDeparture = this.Departure;
        string tmpDestination = this.Destination;
        this.OnLogUpdate("Taking off from " + tmpDeparture + " now.");
        this.Destination = tmpDeparture;
        Thread.Sleep(1000);
        this.OnLogUpdate("Arriving in " + tmpDestination + " now.");
        this.Departure = tmpDestination;
    }

    protected virtual void OnLogUpdate(string logMessage)
    {
        MessageEventArgs e = new MessageEventArgs();
        if (logMessage == "")
            return;
        e.msgContent = logMessage;
        LogMessage(this, e);
    }
}
它会在, 日志消息(本,e)

我不明白,当我在另一个类中有一个几乎相同的设置并且运行良好时,为什么会导致上述异常。 此外,在使用变量检查器进行检查时,设置了
this
e
,因此不为空

我对C#还是有点陌生,尤其是事件和代表,所以我可能错过了一些或多或少明显的东西

[编辑]

如果是因为事件没有订阅,那么这有什么问题

public partial class MainForm : Form
{
    Airport airport = new Airport();
    Flight flight = new Flight();
    public MainForm()
    {
        InitializeComponent();
        InitializeEvents();
    }
    private void InitializeEvents()
    {
        this.airport.ErrorMessage += new System.EventHandler(OnErrorReceived);
        this.flight.LogMessage += new System.EventHandler(OnLogReceived);
    }

机场错误消息的订阅工作正常,但航班日志消息的订阅工作不正常?

日志消息是一个事件,未被其他类订阅。您应该在触发它之前检查它是否为null

if (LogMessage != null)
{
    LogMessage(this, e);
}

LogMessage是一个事件,未被其他类订阅。您应该在触发它之前检查它是否为null

if (LogMessage != null)
{
    LogMessage(this, e);
}

我建议将这一行添加到您的
Flight
对象构造函数中

LogMessage += (s, o) => {};
这将向您的事件添加一个虚拟处理程序,您可以使用它,而无需每次都检查它的可空性,但它有很高的开销,如果有人将
LogMessage
设置为空,则会发出隆隆声<代码>NullPointerException

另一个选项是在每次要触发事件时检查可空性

if(LogMessage != null)
{
   LogMessage(this, e);
}
但是,当线程A检查
LogMessage
是否为null且不为null,线程B将
LogMessage
设置为null,然后线程A触发
LogMessage
并启动时,这可能会造成多线程场景中的争用条件<代码>空点异常

最好的办法就是这样做

protected virtual void OnLogUpdate(string logMessage)
{
    if (logMessage == "")
        return;

    MessageEventArgs e = new MessageEventArgs();
    var handler = LogMessage;

    if (handler != null)
    {
        e.msgContent = logMessage;
        handler(this, e);
    }
}

我建议将这一行添加到您的
Flight
对象构造函数中

LogMessage += (s, o) => {};
这将向您的事件添加一个虚拟处理程序,您可以使用它,而无需每次都检查它的可空性,但它有很高的开销,如果有人将
LogMessage
设置为空,则会发出隆隆声<代码>NullPointerException

另一个选项是在每次要触发事件时检查可空性

if(LogMessage != null)
{
   LogMessage(this, e);
}
但是,当线程A检查
LogMessage
是否为null且不为null,线程B将
LogMessage
设置为null,然后线程A触发
LogMessage
并启动时,这可能会造成多线程场景中的争用条件<代码>空点异常

最好的办法就是这样做

protected virtual void OnLogUpdate(string logMessage)
{
    if (logMessage == "")
        return;

    MessageEventArgs e = new MessageEventArgs();
    var handler = LogMessage;

    if (handler != null)
    {
        e.msgContent = logMessage;
        handler(this, e);
    }
}


你能把它缩小到最小的代码集吗@完成后,删除了大部分不相关的代码(至少与此问题无关)'LogMessage'是一个事件。如果没有人订阅该事件,则该事件将为null。几乎所有的
NullReferenceException
情况都是相同的。请参阅“”,以获得一些提示。@JohnSaunders我已经看过了,这并不是说我不知道通常是什么导致了NullReferenceException,但这种情况有所不同,我想……你能把它缩小到最小的代码集吗@完成后,删除了大部分不相关的代码(至少与此问题无关)'LogMessage'是一个事件。如果没有人订阅该事件,则该事件将为null。几乎所有的
NullReferenceException
情况都是相同的。请参阅“”,以获得一些提示。@JohnSaunders我已经看过了,这并不是说我不知道通常是什么导致了NullReferenceException,但这种情况是不同的,我认为……好的,这修复了异常,谢谢!虽然我不明白为什么它没有被订阅properlyEvent是引用类型,但如果您没有为它设置值,它将为null。您应该在其他类中订阅它,如:Flight Flight=new Flight()Flight.LogMessage+=Func;这将把值设置为LogMessage.and赋值后不为null这不是线程安全好的,修复了异常,谢谢!虽然我不明白为什么它没有被订阅properlyEvent是引用类型,但如果您没有为它设置值,它将为null。您应该在其他类中订阅它,如:Flight Flight=new Flight()Flight.LogMessage+=Func;这会将值设置为LogMessage.and它在赋值后不为null这不是线程安全的谢谢,是的,这一切都是有意义的,除了它为null的原因之外,我仍然不明白,因为我订阅了它,就像订阅了另一个类的类似事件一样。可能
StartFlight()
在按下按钮调用
InitializeEvents
StartFlight()之前被调用,其中InitializeEvents在加载表单的同时被调用。我在Airport ErrorMessage上有一个几乎相同的按钮,效果很好。你应该在代码中跟踪
OnLogUpdate
调用,我想在
InitializeEvents
之前调用
OnLogUpdate
当我在InitializeEvents上设置断点时,它会在我运行调试会话时暂停,因为它在那里进行初始化。当我在OnLogUpDead上有一个断点时,它首先停顿,当我按下我用来触发该方法的按钮时,它仍然认为该日志消息是NullThanks,并且这一切都是有意义的,除了它是空的原因之外,我仍然不明白。因为我订阅了它,就像订阅了另一个类中的类似事件一样。在按下按钮调用
InitializeEvents
StartFlight()之前,可能会调用
StartFlight()
,在加载表单的同时调用InitializeEvents()。我在Airport ErrorMessage上有一个几乎相同的按钮,效果很好。你应该在代码中跟踪
OnLogUpdate
调用,我想在
InitializeEvents
之前调用
OnLogUpdate
当我在InitializeEvents上设置断点时,它会在我运行调试会话时暂停,因为它在那里进行初始化。当我在OnLogUpdate上有一个断点时,当我按下用于触发该方法的按钮时,它首先暂停,此时