Firstly, what is delegate?
A delegate is like a pointer to a function. It holds the reference of a method. All delegates are derived from System.Delegate class.
Syntax of Delegate =>
<access modifier> delegate <return type> <delegate_name>(<parameters>)
e.g. =>
- public delegate void SendMessage(string message);
The SendMessage delegate shown above, can be used to point to any method that has same return type & parameters declared with SendMessage.
What is Event?
Events enable a class or object to notify other classes or objects when something of interest occurs. The class that sends (or raises) the event is called the publisher and the classes that receive (or handle) the event are called subscribers. An event has a publisher, subscriber, notification and a handler. Practically, an event is nothing but an encapsulated delegate.
Syntax of Events =>
<access modifier> event <delegate_name> EventName;
OR
<access modifier> event EventHandler<custom event class> EventName;
OR
<access modifier> event Eventhandler EventName;
e.g.
- public event MessageLoggedEventHandler MessageLogged;
The main use of events and delegates is to make objects loosely coupled. I will show you how this helps.
Now lets start. We will create a LoggerService which will write the Logs and once the log are written it will send the Mail/Message based on the events subscribed.
First let's create a Logger class (Publisher) which will be responsible for publishing the Event.
-
-
-
-
-
-
-
- public class Logger
- {
- public delegate void DataLoggedEventHandler(object source, EventArgs args);
- public event DataLoggedEventHandler MessageLogged;
- public void WriteLog(string message)
- {
- Console.WriteLine($"Message: {message}");
- Thread.Sleep(4000);
- OnMessageLogged();
- }
-
- protected virtual void OnMessageLogged()
- {
- if (MessageLogged != null)
- MessageLogged(this, EventArgs.Empty);
- }
- }
In the above code, we created a delegate (DataLoggedEventHandler) to hold the reference of the method having same signature. Secondly, we created an event for DataLoggedEventHandler delegate which will allow the subscriber to subscribe.
Finally, we created an OnMessageLogged() event method responsible for invoking respective method subscribed.
Now we will create a MailService class (Subscriber) which would be responsible for sending mail once the event occurs.
- public class MailService
- {
- public void OnMessageLogged(object source,EventArgs args)
- {
- Console.WriteLine("Sending Mail...");
- Thread.Sleep(3000);
- Console.WriteLine("Mail Sent");
- }
- }
Note here, the method signature is same as that of delegate.
Now let's create a Main() class which would subscribe the events and will invoke the WriteLog() method.
- public class LoggerService
- {
- static void Main()
- {
- var logger = new Logger();
- var mailer = new MailService();
-
- #region Subscribe Events
- logger.MessageLogged += mailer.OnMessageLogged;
- #endregion
-
-
- logger.WriteLog("This is an error log");
-
- Console.WriteLine("Event Completed");
- Console.Read();
- }
- }
Now let's see how it is loosely coupled. Lets say I need to add a new service called MessageService and also want to subscribe the event and invoke action need to be performed OnMessageLogged() for MessageService.
- public class MessageService
- {
- public void OnMessageLogged(object source, EventArgs args)
- {
- Console.WriteLine("Sending Message...");
- Thread.Sleep(3000);
- Console.WriteLine("Message Sent");
- }
- }
Now if I need to plug it similar to MailService then I need to make changes in only Calling(Main) class.
- public class LoggerService
- {
- static void Main()
- {
- var logger = new Logger();
- var mailer = new MailService();
- var messenger = new MessageService();
-
- #region Subscribe Events
- logger.MessageLogged += mailer.OnMessageLogged;
- logger.MessageLogged += messenger.OnMessageLogged;
- #endregion
-
-
- logger.WriteLog("This is an error log");
-
- Console.WriteLine("Event Completed");
- Console.Read();
- }
- }
Run the app and see the output.
Okay. Now we are quite clear with the concepts of Events and Delegate and how they both works together.
Now lets say if we need to send the message through event then how can we achieve it.
I will create a CustomEvent say LoggerEvent by inheriting from EventArgs.
- public class LoggerEvents : EventArgs
- {
- public string Message { get; set; }
- }
Now we will use this event to send the message. Lets see the required changes in Logger class,
- public class Logger
- {
- public delegate void DataLoggedEventHandler(object source, EventArgs args);
- public delegate void DataLoggedEventHandler(object source, LoggerEvents args);
- public event DataLoggedEventHandler MessageLogged;
- {
- Console.WriteLine($"Message: {message}");
- Thread.Sleep(4000);
- OnMessageLogged();
- OnMessageLogged(message);// raise event
- }
-
- protected virtual void OnMessageLogged()
- protected virtual void OnMessageLogged(string message)
- {
- if (MessageLogged != null)
- MessageLogged(this, EventArgs.Empty);
- MessageLogged(this, new LoggerEvents() { Message = message });
- }
- }
Now with these changes we also need to update the Subscriber classes to accomodate custom event.
- public class MailService
- {
- public void OnMessageLogged(object source,EventArgs args)
- public void OnMessageLogged(object source, LoggerEvents args)
- {
- Console.WriteLine("Sending Mail...");
- Thread.Sleep(3000);
- Console.WriteLine("Mail Sent");
- Console.WriteLine($"Mail Sent with message - {args.Message}");
- }
- }
- public class MessageService
- {
- public void OnMessageLogged(object source, EventArgs args)
- public void OnMessageLogged(object source, LoggerEvents args)
- {
- Console.WriteLine("Sending Message...");
- Thread.Sleep(3000);
- Console.WriteLine("Message Sent");
- Console.WriteLine($"Message Sent with message - {args.Message}");
- }
- }
Now just run it and the output would be same.
Finally, one more enhancement to Logger class (Publisher) to use EventHandler instead of delegate. .Net came up with EventHandler from .Net Framework 2.0 version so we can use it instead of delegates. Lets see how we can make the changes and get the same output with minimize code.
- public class Logger
- {
-
-
- //public event DataLoggedEventHandler MessageLogged;
-
- public event EventHandler<LoggerEvents> MessageLogged;
-
-
- public void WriteLog(string message)
- {
- Console.WriteLine($"Message: {message}");
- Thread.Sleep(4000);
- OnMessageLogged(message);
- }
-
-
- protected virtual void OnMessageLogged(string message)
- {
- if (MessageLogged != null)
- MessageLogged(this, new LoggerEvents() { Message = message });
- }
- }
With the above changes, we removed creation of delegate and instead used the EventHandler. Run the app you should get the same o/p.
Thats it. Here, I covered the concepts of events, delegates and event handlers in C#.