Why my custom event in C# is not raised?

5.1k views Asked by At

It's not the first time I've created a Custom Event in C#. It boggles my mind why it doesn't work in this simple case.

I have a Publisher with Subscribers. In my main program, I instantiated 1 publisher and 2 subscribers. When addNews is called, Subscribers should receive the event NewPublication:

static void Main()
{
    Publisher publisher = new Publisher();
    Subscriber subscriber1 = new Subscriber("John");
    Subscriber subscriber2 = new Subscriber("Jane");

    publisher.AddNews("custom event NewPublication");   
}

In subscriber.cs I have:

public delegate void NewPublication(Publisher fromPublisher, String Message);

public class Publisher {

    private List<String> newsList = new List<String>();
    public event NewPublication newPublication;

    public void AddNews(String news) {
        newsList.Add(news);

        if (newPublication != null)
        {
            newPublication(this, news);
        }
    }
}

In Subscriber I have:

private String m_Name;
private event NewPublication newPublication;


public Subscriber(String name) {
    m_Name = name;
    newPublication += new NewPublication(subscriber_newPublication);
}

public void subscriber_newPublication(Publisher fromPublisher, String Message) {
    MessageBox.Show(m_Name + " is notified for " + Message);
}

It compiles, but when running, the event is never raised. Why not? How can I fix my code so that it does get raised?

What's really different from MSDN sample code: http://msdn.microsoft.com/en-us/library/w369ty8x.aspx

2

There are 2 answers

1
ShdNx On BEST ANSWER

It appears that you actually have 2 newPublication events: one in Subscriber and one in Publisher. You're raising the one in Publisher, but the Subscribers only subscribe to their own event.

Here is how your Subscriber class should work:

private String m_Name;
private Publisher m_Publisher;

public Subscriber(String name, Publisher publisher) {
     m_Name = name;
     m_Publisher = publisher;
     m_Publisher.newPublication += new NewPublication(subscriber_newPublication);
}

public void subscriber_newPublication(Publisher fromPublisher, String Message) {
    MessageBox.Show(m_Name + " is notified for " + Message);
}

For the ease of use, you might want to introduce a Subscribe method to your Publisher class, like so:

public Subscriber Subscribe(String name)
{
     return new Subscriber(name, this);
}

Note that event handlers that are attached, but never detached and that can cause memory leaks in your .NET application. Always use the -= operator to detach event handlers when you no longer need them (for example in a WinForms application I usually detach the event handlers for control events when the FormClosed event is fired). Here is a good article that explains it in depth, and here is another one that demonstrates the detection of memory leaks.

For an advanced event concept you might want to familiarize yourself with F#'s and the Reactive Framework's event model (which are also free of memory leaks), as described in this series of articles.

2
Ondrej Tucny On

You've declared two distinct events. Your publisher instance and subscriber instances are not connected in any way. Hence raising the event in the publisher won't trigger the handlers in the subscribers.

What you need to do is schematically:

publisher.newPublication += subscriber1.subscriber_newPublication;
publisher.newPublication += subscriber2.subscriber_newPublication;

Place this code between instantiation of these classes and calls to AddNews().

Update: Hence the declaration of newPublication in the Subscriber class is completely useless and shall be removed from that class. If you need, you can pass the Publisher instance into a Subscriber's constructor to make the event wiring within the Subscriber. However, it's generally a good idea to keep event wiring code outside both event publishers and event subscribers.