Blue Theme Orange Theme Green Theme Red Theme
 
MindFusion's Components
Home | Forums | Videos | Photos | Downloads | Blogs | E-Books | Interviews | Jobs | Beginners | Training
 | Consulting  
Submit an Article Submit a Blog 
 Login Close
User Id:
Password:
 
Forgot Password
Forgot Username
Why Register
 Jump to
Skip Navigation Links
TechnologyExpand Technology
WebsiteExpand Website
 Resources  
Close
 Our Network  
Close
Search :       Advanced Search »
Home » C# Language » C# Defensive Event Publishing using Interfaces

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.

Author Rank:
Technologies: .NET 1.0/1.1,Visual C# .NET
Total downloads : 910
Total page views :  22579
Rating :
 4.22/5
This article has been rated :  9 times
   Print Read/Post comments Post a comment  Rate  
   Email to a friend  Bookmark  Similar Articles  Author's other articles  
Download Files:
Sample3.zip | Sample2.zip | Sample1.zip
 
Become a Sponsor



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 purposely 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, which is to provide behavioral contracts between 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, 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...
 

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:

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

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

In Conclusion

To avoid unwanted guests are 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 -- 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


Login to add your contents and source code to this article
 [Top] Rate this article
 About the author
 
Matthew Cochran
Looking for C# Consulting?
C# Consulting is founded in 2002 by the founders of C# Corner. Unlike a traditional consulting company, our consultants are well-known experts in .NET and many of them are MVPs, authors, and trainers. We specialize in Microsoft .NET development and utilize Agile Development and Extreme Programming practices to provide fast pace quick turnaround results. Our software development model is a mix of Agile Development, traditional SDLC, and Waterfall models.
Click here to learn more about C# Consulting.
 
Introducing MaxV - one click. infinite control. Hyper-V Hosting from MaximumASP.
Finally – a virtual platform that delivers next-generation Windows Server 2008 Hyper-V virtualization technology from a managed hosting partner you can truly depend on. Visit www.maximumasp.com/max for a FREE 30 day trial. Hurry offer ends soon. Climb aboard the MaxV platform and take advantage of High Availability, Intelligent Monitoring, Recurrent Backups, and Scalability – with no hassle or hidden fees. As a managed hosting partner focused solely on Microsoft technologies since 2000, MaximumASP is uniquely qualified to provide the superior support that our business is built on. Unparalleled expertise with Microsoft technologies lead to working directly with Microsoft as first to offer IIS 7 and SQL 2008 betas in a hosted environment; partnering in the Go Live Program for Hyper-V; and product co-launches built on WS 2008 with Hyper-V technology.
Dynamic PDF
ceTE software specializes in components for dynamic PDF generation and manipulation. The DynamicPDF™ product line allows you to dynamically generate PDF documents, merge PDF documents and new content to existing PDF documents from within your applications.
Go.NET
Build custom interactive diagrams, network, workflow editors, flowcharts, or software design tools. Includes many predefined kinds of nodes, links, and basic shapes. Supports layers, scrolling, zooming, selection, drag-and-drop, clipboard, in-place editing, tooltips, grids, printing, overview window, palette. 100% implemented in C# as a managed .NET Control. Document/View/Tool architecture with many properties&events. Optional automatic layout.
Dundas Software
Dundas Chart for .NET is the most advanced .NET charting package available today.  With an extremely complete feature set, elegant architecture and easy implementation, Dundas Chart can quickly add advanced Charting functionality to enhance and transform ASP.NET and Windows Forms applications.  Whether you are implementing charting into internal projects, or building applications for clients, Dundas Chart offers advanced technology and advanced results to get the most out of data.
Clickatell's SMS Gateway
Clickatell's Developer Solutions allow you to SMS enable any website or application via a range of API's. Learn More about our API connections.
Free access to .NET Memory Management video
Everything you need to know about Garbage Collection, Temporary Objects, Fragmentation, Finalization and common causes of memory leaks in .NET. Watch the video here.
Microsoft Visual Studio 2010
Microsoft Visual Studio 2010 offers more to developers than any other Visual Studio release. Work more productively and collaboratively-with greater control over your work at every step. The Beta 2 can give you a head start on achieving efficiency.
 
   Print Read/Post comments Post a comment  Rate  
   Email to a friend  Bookmark  Similar Articles  Author's other articles  
Download Files:
Sample3.zip | Sample2.zip | Sample1.zip
 
 Post a Feedback, Comment, or Question about this article
Subject:  
Comment:  
Dundas Dashboard
Become a Sponsor
 Comments
Thanks :) by Farzad On January 2, 2009
Your article was very useful for me. Thanks! :) Farzad Badili
Reply | Email | Delete | Modify | 
Support for multiple event delegates? by Richard On January 15, 2009
Great article. Does this support multiple event delegates? All examples using this design are specific to bindable objects that use the interfaces to raise "dirty" events to subscribers. Thanks.
Reply | Email | Delete | Modify | 

 Hosted by MaximumASP  |  Found a broken link?  |  Contact Us  |  Terms & conditions  |  Privacy Policy  |  Site Map  |  Suggest an Idea  |  Media Kit
Current Version: 5.2009.6.2
 © 1999 - 2009  Mindcracker LLC. All Rights Reserved