Have Your Foot in the Door with Delegate and Events





5.00/5 (1 vote)
Have your foot in the door with delegates and events
Delegate and events are one of the most used techniques in a program. In my opinion, people use them most but write them the least. Recently, one of my juniors asked me about an explanation about delegate and event and this is the reason why I am here sitting and writing for the next generation programmers.
Frankly speaking, delegates are a kind of an advanced version of function pointer. Those who are familiar with C/C++ know that function pointers are a special type of pointers that store the address of a function in the stack. This address can be passed freely throughout the program and later on when needed, can be executed anywhere of the program.
On the other side, events are a kind of signal in C/C++. These signals can be raised by your program as like a signal can be raised by the Operating System when you plug-in a USB stick; but someone out there needs to listen the signals and handle them properly.
Well, all those are theoretical and now we can go to the practical use of it. Delegates and events are used in scenarios where we need publish-subscribe pattern. Now that is publish-subscribe pattern? Hit on wiki here for a detailed description. But in a nutshell, The Publishers will raise a signal and the subscribers will listen to those signals and act accordingly. What I want to emphasize on public subscriber pattern is The Publisher should not have any knowledge of who are The Subscribers are, and The Subscribers should not have any interaction with The Publishers, except one thing – listening to The Publisher’s event.
In Publisher.cs
So now, we have a publisher class where we need a delegate and delegate-type-variable. As I discussed above that the delegate will point to a function, so it must specify a function signature.
public delegate bool NewEditionPublishHandler
(object Publisher, string EditionName , int EditionNr);
This function signature is the type of the delegate-variable.
public NewEditionPublishHandler Publish;
Later in Publisher, this delegate-variable will point a function in the Subscriber
class so that the publisher can call that function using this delegate-variable.
public delegate bool NewEditionPublishHandler(object Publisher, string EditionName , int EditionNr);
public NewEditionPublishHandler Publish;
… … …
Publish(this, "Harry Potter" , i++);
Notice that Publisher
is calling a function of a Subscriber
without any knowledge of it. No reference, no variable, no knowledge at all, except the face that the subscriber must listen to the signal sent by the publisher, i.e., Subscriber
must subscribe a function to that signal and of course that function signature should be the same as that delegate-type.
At the subscriber class, this is done by the following code:
In Subscriber.cs
public void SubscriberToPublisher(Publisher publisher)
{
publisher.Publish += new Publisher.NewEditionPublishHandler(ShowPublicationDetail);
//or (event subscription with delegate keyword)
publisher.Publish += delegate(object SubscribedPublisher,
string publicationName, int publilcationNr) { … return True };
//or (event subscription with linq expression)
publisher.Publish += (SubscribedPublisher, publicationName, publilcationNr) => { … return True;};
}
The above three statements are doing the same task with three different syntaxes:
Here two interesting things are happening.
Subscriber
is subscribing itself to a signal of thepublisher
–Subscriber
is binding an anonymous function with the signal of the publisher so that whenever a signal is raised from thepublisher
, this function will be executed.Publisher
is delegating its task to theSubscribers
–Publisher
is delegating its task to thesubscribers
function so whenever the publisher is calling the delegate-variable, it’s thesubscribers
anonymous function gets executed.
In Program.cs
In our program, somewhere we need to create a publisher
and a subscriber
and subscribe to the publisher
.
Publisher P = new Publisher();
Subscriber S = new Subscriber();
S.SubscriberToPublisher(P);
Subscriber2 S2 = new Subscriber2();
S2.SubscriberToPublisher(P);
Finally run the publishers PublishRegularly().
P.PublishRegularly();
This PublishRegularly()
function will in a regular interval call the delegate-variable with appropriate perimeters. This delegate-variable which will in turn delegate its task along with its parameter to the subscriber
’s anonymous function and get the job done by the subscriber
.
public void PublishRegularly()
{
while (true)
{
Thread.Sleep(2000);
if (Publish != null)
{
Publish(this, "Harry Potter (pert " + i.ToString() + ") ", i++);
}
}
}
Notice that we are doing a check ((Publish != null)
). This is done because if there is no subscriber
subscribing to the publisher
, the publisher
can still run the function, i.e., the publisher
is completely ignoring whether any subscriber
is subscribing to it or not.
Even if there is more than one subscriber
subscribing, it does not matter to the publisher
either. It’s the subscriber
's responsibility to listen to the publisher
's signal and act accordingly with the help if its own anonymous function.
Event
Now in the Publisher.cs file, change the declaration of the delegate type-variable like this:
public NewEditionPublishHandler Publish;
public event NewEditionPublishHandler Publish;
And in the Subscriber.cs, change the publisher
's signal subskribtion(event subskribtion) like this:
publisher.Publish += (SubscribedPublisher, publicationName, publilcationNr) =>{…}
publisher.Publish = (SubscribedPublisher, publicationName, publilcationNr) =>{…}
With this, you will get an error:
Error 1 The event 'Delegate_Event_Test.Publisher.Publish' can only appear
on the left hand side of += or -= (except when used from within the type 'Delegate_Event_Test.Publisher')
C:\Users\rizvis\Documents\Visual Studio 2010\Projects Test\Delegate_Event_Test\Delegate_Event_Test\Subscriber.cs
23 23 Delegate_Event_Test.
Thanks to ‘event’ for making this error because with the statement:
publisher.Publish = (SubscribedPublisher, publicationName, publilcationNr) =>{…}
Here, you are not subscribing a signal from a delegate-variable, rather you assigning a wrong value to it. This is wrong and your program will not work as it is intended. Without the ‘event
’ keyword, you will not get a compilation error and thus you are planting a bug in your code. So with the ‘event
’ keyword even if you missed +=
with =
, it will show up at compile time.
Bird’s eye view
So with a delegate, we are preparing an object (i.e. Publisher
) to emit a signal to another set of objects (i.e. Subscribers
) who are subscribed with publishers' signal with an anonymous function. As a notification of the signal, the subscribers
will execute their own function. So simple!