ARTICLE

VB.Net Defensive Event Publishing using Interfaces

Posted by Matthew Cochran Articles | Visual Basic 2010 November 16, 2006
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 VB.Net event model is based on the Observer GOF pattern.
Download Files:
 
Reader Level:

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 VB.Net event model is based on the Observer GOF pattern. 

If you are interested in the relation between the Observer pattern and the VB.Net 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 SomeEvent As SomeEventHandler

 

    Delegate Sub SomeEventHandler(ByVal pub As Publisher)

  

    Public Sub FireTheEvent()

        If Nothing <> SomeEvent Then

            SomeEvent.Invoke(Me)

        End If

    End Sub 'FireTheEvent

End Class 'Publisher

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 m_SomeEvent As SomeEventHandler

 

    Delegate Sub SomeEventHandler(ByVal pub As Publisher)

 

    Public Sub FireTheEvent()

        If Nothing <> m_SomeEvent Then

            m_SomeEvent.Invoke(Me)

        End If

    End Sub 'FireTheEvent

End Class 'Publisher


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 m_number As Integer

     

        Public Property Number() As Integer

            Get

                Return m_number

            End Get

            Set(ByVal value As Integer)

                m_number = value

            End Set

        End Property

     

        Delegate Sub MyEventDelegate()

        Private Event m_event As MyEventDelegate

     

    End Class '[MyClass]

     

  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. 

    Delegate Sub MyEventDelegate()

     

    Public Interface MyEventInterface

        Event MyEvent As MyEventDelegate

    End Interface 'MyEventInterface

     

    Public Class [MyClass]

        Inherits MyEventInterface

        Private m_number As Integer

     

        Public Property Number() As Integer

            Get

                Return m_number

            End Get

            Set(ByVal value As Integer)

                m_number = value

            End Set

        End Property

     

        Private Event m_event As MyEventDelegate

     

    End Class '[MyClass]

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

    Sub RegisterListener(ByVal listener As IEventListener)

    Sub UnregisterListener(ByVal listener As IEventListener)

    Sub NotifyListeners()

End Interface 'IEventPublisher

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

Sub RegisterListener<T>(T listener) where T Implements IeventListener

Sub UnregisterListener<T>(T listener) where T Implements IEventListener

Sub NotifyListeners()

End Interface

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

    Sub OnNotification(ByVal publisher As IEventPublisher)

End Interface 'IEventListener

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

    Implements IEventPublisher

 

    Delegate Sub m_eventHandler(ByVal publisher As IEventPublisher)

    Private Event m_event As m_eventHandler

 

    Public Sub RegisterListener(ByVal listener As IEventListener)

        AddHandler m_event, AddressOf listener.OnNotification

    End Sub 'RegisterListener

 

    Public Sub UnregisterListener(ByVal listener As IEventListener)

        m_event -= New m_eventHandler(listener.OnNotification)

    End Sub 'UnregisterListener

 

    Public Sub NotifyListeners()

        If Nothing <> m_event Then

            m_event(Me)

        End If

    End Sub 'NotifyListeners

End Class 'Publisher

And our Listener class...
 

Public Class Listener

    Implements IEventListener

    Public Sub OnNotification(ByVal publisher As IEventPublisher)

  Console.WriteLine(String.Format("{0} fired an event", publisher.GetType().ToString()))

    End Sub 'OnNotification

End Class 'Listener

 

And finally we can wire it up:

Class Main

     Public Sub Run()

        Dim list As New Listener()

        Dim pub As New Publisher()

 

        pub.RegisterListener(list)

        pub.NotifyListeners()

    End Sub 'Run

End Class 'Main

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 VB.Net 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

NOTE: THIS ARTICLE IS CONVERTED FROM C# TO VB.NET USING A CONVERSION TOOL. ORIGINAL ARTICLE CAN BE FOUND ON C# CORNER (http://www.c-sharpcorner.com/).  

Login to add your contents and source code to this article
share this article :
post comment
 
Nevron Diagram
Become a Sponsor
PREMIUM SPONSORS
  • The leading .NET charting control now features PDF, Flash and Silverlight export, visualization of large datasets and more. Deliver true charting functionality to your BI, Scorecard, Presentation or Scientific apps. Download evaluation now.
    Get 2 Months Free of ASP.NET Hosting for Only $4.95/month! Receive FREE MS SQL and MySQL Databases Including ASP.NET 4/3.5, MVC 3.0, Silverlight 4, Windows 2008/IIS 7.0 Plus FREE IIS 7 Modules. Host UNLIMITED ASP.NET Web Sites - Click Here!
Become a Sponsor