1

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

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.

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

[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?

Hamid Pourjam
  • 18,954
  • 8
  • 53
  • 67
Ronin
  • 65
  • 8
  • Can you narrow this down to a minimal code set? http://stackoverflow.com/help/mcve – Reticulated Spline Dec 10 '14 at 00:29
  • @ReticulatedSpline Done, removed most of the irrelevant code ( irrelevant to this problem at least ) – Ronin Dec 10 '14 at 00:32
  • 1
    'LogMessage' is an event. If nobody susbcribes to the event, it will be null. – Zanon Dec 10 '14 at 00:34
  • Almost all cases of `NullReferenceException` are the same. Please see "[What is a NullReferenceException in .NET?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-in-net)" for some hints. – John Saunders Dec 10 '14 at 00:52
  • @JohnSaunders I already looked through that, and its not that i don't know what causes a NullReferenceException in general, but this case is different, i think... – Ronin Dec 10 '14 at 00:55
  • This case is identical, and I believe there's an example in the linked question: nobody has subscribed to the event, so it's `null`. Check for null and set a breakpoint when it's null. You'll be able to see why it's `null`. – John Saunders Dec 10 '14 at 01:48
  • @JohnSaunders the thing is, that it is subscribed, just like another almost identical working event is – Ronin Dec 10 '14 at 07:45
  • It's not subscribed by the time you try to invoke it. Add a null check and I bet your problem goes away. Or set a breakpoint and see if it's null again by the time you invoke. – John Saunders Dec 10 '14 at 13:23
  • @JohnSaunders that much makes sense, and i have done both, and yes a null check does avoid the exception, but it doesn't fix the actual problem. Guess i should rephrase, or rephrase and re-ask the question? since the problem is, that it "is" subscribed ( well, apart from it apparently not being subscribed...) – Ronin Dec 10 '14 at 14:55

2 Answers2

2

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

if (LogMessage != null)
{
    LogMessage(this, e);
}
Hamid Pourjam
  • 18,954
  • 8
  • 53
  • 67
Phenix_yu
  • 284
  • 2
  • 5
  • Okay, that fixed the exception, thanks! Although i dont understand why it isn't subscribed properly – Ronin Dec 10 '14 at 00:35
  • Event is reference type,if you donot set value to it,it's null.You should subscribe it in other class like this: Flight flight=new Flight() flight.LogMessage+=Func; This will set value to LogMessage.and it's not null after assignment – Phenix_yu Dec 10 '14 at 00:40
  • this is not thread safe – Hamid Pourjam Dec 10 '14 at 00:42
2

I suggest to add this line to your Flight object constructor

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.

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

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);
    }
}
Hamid Pourjam
  • 18,954
  • 8
  • 53
  • 67
  • Thanks, and yea it all makes sense this way, except for the cause of it being null, i still don't understand that, as i have it subscribed like i have with a similar event from another class. – Ronin Dec 10 '14 at 00:51
  • maybe `StartFlight()` is called before `InitializeEvents` – Hamid Pourjam Dec 10 '14 at 01:00
  • StartFlight() is called on a button press, where InitializeEvents are called at the same time the Form loads up. I have a almost identical button for the Airport ErrorMessage which works fine – Ronin Dec 10 '14 at 01:03
  • you should track `OnLogUpdate` calls in your code, I think somewhere `OnLogUpdate` is called before `InitializeEvents ` – Hamid Pourjam Dec 10 '14 at 01:08
  • When i set a breakpoint on InitializeEvents it pauses as soon as i run a debug session, since it does the initializing there. and When i have a breakpoint on OnLogUpdate, it first pauses when i press the button that i use to trigger the method, at which point it still consider the LogMessage to be Null – Ronin Dec 10 '14 at 01:14
  • can you upload your code somewhere? – Hamid Pourjam Dec 10 '14 at 01:16
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/66530/discussion-between-ronin-and-dotctor). – Ronin Dec 10 '14 at 01:46