触发事件时发生NullReferenceException [重复]

时间:2021-07-19 00:03:46

This question already has an answer here:

这个问题在这里已有答案:

i have this code I'm playing around with, but it causes a, for me at least, weird exception.

我有这个代码我正在玩,但它至少对我来说是奇怪的异常。

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);
    }
}

It causes a NullReferenceException at the, LogMessage(this, e);

它在LogMessage(this,e)处导致NullReferenceException;

I don't understand why it causes said exception when i have a practically identical setup in another class that works fine. Also, when checking with the variable inspector, both this and e is set, and therefor not Null.

我不明白为什么它导致所述异常,当我在另一个类中具有几乎相同的设置时工作正常。此外,在使用变量检查器进行检查时,将设置this和e,因此不会为Null。

I'm still a somewhat new to C#, and especially events and delegates, so i have probably missed something more or less obvious

我对C#还是一个新手,特别是事件和代表,所以我可能错过了一些或多或少的东西

[Edit]

[编辑]

If it is because the event have no subscriptions, what is wrong with this?

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

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);
    }

the subscription for the airport error message is working fine, but the one for the flight LogMessage doesn't?

机场错误消息的订阅工作正常,但一个航班LogMessage没有?

2 个解决方案

#1


2  

I suggest to add this line to your Flight object constructor

我建议将此行添加到Flight对象构造函数中

LogMessage += (s, o) => {};

this will add a dummy handler to your event and you can use it without checking for it's nullability every time but it has high overhead and if somebody set LogMessage to null then boom! NullPointerException.

这将为你的事件添加一个虚拟处理程序,你可以使用它而不必每次都检查它的可空性,但它有很高的开销,如果有人将LogMessage设置为null然后繁荣!空指针异常。

another option is to check for nullability every time you want to fire your event

另一个选择是每次你想要发射你的事件时检查是否为空

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

but this can make race conditions in multi-thread scenarios when thread A check if LogMessage is null and it is not null and thread B set LogMessage to null and then thread A fires the LogMessage and boom! NullPointerException

但是当线程A检查LogMessage是否为null并且它不为null并且线程B将LogMessage设置为null然后线程A触发LogMessage并且繁荣时,这可以在多线程场景中产生竞争条件!空指针异常

the best way is to do it like this

最好的方法就是这样做

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);
    }
}

#2


2  

LogMessage is an event and not subscribed by other class. you should check if it's null before you trigger it

LogMessage是一个事件,不是由其他类订阅的。你应该在触发它之前检查它是否为null

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

#1


2  

I suggest to add this line to your Flight object constructor

我建议将此行添加到Flight对象构造函数中

LogMessage += (s, o) => {};

this will add a dummy handler to your event and you can use it without checking for it's nullability every time but it has high overhead and if somebody set LogMessage to null then boom! NullPointerException.

这将为你的事件添加一个虚拟处理程序,你可以使用它而不必每次都检查它的可空性,但它有很高的开销,如果有人将LogMessage设置为null然后繁荣!空指针异常。

another option is to check for nullability every time you want to fire your event

另一个选择是每次你想要发射你的事件时检查是否为空

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

but this can make race conditions in multi-thread scenarios when thread A check if LogMessage is null and it is not null and thread B set LogMessage to null and then thread A fires the LogMessage and boom! NullPointerException

但是当线程A检查LogMessage是否为null并且它不为null并且线程B将LogMessage设置为null然后线程A触发LogMessage并且繁荣时,这可以在多线程场景中产生竞争条件!空指针异常

the best way is to do it like this

最好的方法就是这样做

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);
    }
}

#2


2  

LogMessage is an event and not subscribed by other class. you should check if it's null before you trigger it

LogMessage是一个事件,不是由其他类订阅的。你应该在触发它之前检查它是否为null

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