C# Defensive Event Publishing Using Interfaces

In order to ensure that our events behave as intended we can use interfaces to control access, the classes that subscribe to the events and the event registration process. To do this, we can write "observer"-type interfaces for notification, subscription and un-subscription to events because the C# event model is based on the Observer GOF pattern. 

If you are interested in the relation between the Observer pattern and the C# event model, or if you don't have a clear understanding of events, check out my article on events here.

If you are new to interfaces, check out my article on interface based development here.

Event Publication

Events can be exposed publicly this way:   

public class Publisher
{
   
public event SomeEventHandler SomeEvent;
   
public delegate void SomeEventHandler(Publisher pub);

    public void FireTheEvent()
    {
        
if (null != SomeEvent)
              SomeEvent.Invoke(
this);
    }
}

Events can also be exposed through the event properties, using the "add" and "remove" keywords, as in the class below:

 

public class Publisher
{
    
private event SomeEventHandler m_SomeEvent;
    
public delegate void SomeEventHandler(Publisher pub);

     public event SomeEventHandler SomeEvent
     {
         
add { m_SomeEvent +=new SomeEventHandler(value); }
         
remove{ m_SomeEvent -= new SomeEventHandler(value); }
     }

     public void FireTheEvent()
     {
         
if (null != m_SomeEvent)
              m_SomeEvent.Invoke(
this);
     }
}


If you choose to publish your events publically, I would recommend using the "add" and "remove" keywords for a couple of reasons.

  1. For code consistency, your event publication should follow the pattern used to expose the private member variables.

    public class MyClass
    {
       
    private int
    m_number;
       
    public int
    Number
        {
            
    get { return
    m_number; }
            
    set { m_number = value
    ; }
        }
       
    public delegate void MyEventDelegate();
       
    private event MyEventDelegate m_event;
       
    public event MyEventDelegate
    MyEvent
        {
            
    add { m_event += new MyEventDelegate(value
    ); }
            
    remove { m_event -= new MyEventDelegate(value
    ); }
        }
    }

     

  2. If you need to implement the same method explicitly and in addition need to expose it implicitly through an interface member, you will need to use the event properties. 

    public delegate void MyEventDelegate();

    public interface MyEventInterface
    {
         event MyEventDelegate MyEvent;
    }

    public class MyClass: MyEventInterface
    {
         private int m_number;
         public int Number
         {
             get { return m_number; }
             set { m_number = value; }
       }

         private event MyEventDelegate m_event;

         public event MyEventDelegate MyEvent
         {
             add { m_event += new MyEventDelegate(value); }
          remove { m_event -= new MyEventDelegate(value); }
       }

         event MyEventDelegate MyEventInterface.MyEvent
         {
             add { m_event += new MyEventDelegate(value); }
             remove { m_event -= new MyEventDelegate(value); }
       }
    }

The Problem With Public Events

One problem with exposing the event publicly on the class or through the interface is that we don't have control over who actually subscribes to the event.  If we are intentionally exposing the event so anyone and anything can register, that's one thing.  However, this conflicts with one of the primary purposes of an interface, that is to provide behavioral contracts among objects. 

Think of it this way. Let's say we are inviting our family over for a nice dinner and leave a message on voice mail letting them know of the plans.  Alternatively, we could post a large sign outside our front door saying "FREE FOOD!!! - Just come on in.  Dinner served at 8 pm."  We won't know who is going to show up but I bet there will be some unexpected guests for dinner. 

In the first case, we know who is coming to dinner and want some private time together with our family.  On the other hand, if we are truly giving away free food to any passerby, the second option may be best for us and we can publish our dinner event publicly.

Publish Events Defensively

In order to have a little more privacy over our event publication dinner we can leave the event as an implementation tool alone and expose it's functionality through interfaces.  If we follow this route, it leads us to code that looks a lot more like the GOF observer pattern.

Our event publisher will expose functions to register and un-register an object to our event and to notify the observing members.  We will expose all of this through the interface.

public interface IEventPublisher
{
    
void RegisterListener(IEventListener
listener);
    
void UnregisterListener(IEventListener
listener);
     
void
NotifyListeners();
}

As a side note, if we are using the 2.0 framework then we could accomplish the same thing using generics and have a bit more type safety.

public interface IEventPublisher2
{
   
void RegisterListener<T>(T listener) where T:IEventListener
;
   
void UnregisterListener<T>(T listener) where T:IEventListener
;
    
void
NotifyListeners();
}

Our event "listener" interface should preface all of the event driven methods using "On" to make our code more readable and understandable (Whenever you see "On" you should automatically think "there is an event here somewhere").

public interface IEventListener
{
   
void OnNotification(IEventPublisher publisher);
}

Next, we define our publisher.  Notice the delegate and event are both implemented as private member variables, thus removing the large  "FREE FOOD" sign from the front door.

public class Publisher : IEventPublisher
{
    
private delegate void m_eventHandler(IEventPublisher publisher);
    
private event m_eventHandler m_event;

     #region IEventPublisher Members 

     public void RegisterListener(IEventListener listener)
     {
         m_event +=
new m_eventHandler(listener.OnNotification);
     }

     public void UnregisterListener(IEventListener listener)
     {
         m_event -=
new m_eventHandler(listener.OnNotification);
     }

     public void NotifyListeners()
     {
        
if (null != m_event)
              m_event(
this);
     }

     #endregion
}

And our Listener class is:
 

public class Listener : IEventListener
{

     #region IEventListener Members 

     public void OnNotification(IEventPublisher publisher)
     {
        
Console.WriteLine(string.Format(
            
"{0} fired an event"
             publisher.GetType().ToString()));
     }

     #endregion

}

 

And finally we can wire it up as in the following:

class Main
{
    
public void Run()
     {
        
Listener list = new Listener();
        
Publisher pub = new Publisher();

         pub.RegisterListener(list);
         pub.NotifyListeners();
     }
}

In Conclusion

 

To avoid unwanted guests at you dinner party, don't advertise it publicly.  Also, if you don't want uninvited event listeners but want to take advantage of C# event functionality then keep the events to yourself and hide them in the class. This will also make for clearer, more maintainable code.

Until next time,

Happy coding.

Up Next
    Ebook Download
    View all
    Learn
    View all