Saturday, September 12, 2020

Events and Delegates

  • Events is a mechanism for communication between objects. When something happened to an object, It can notify other objects about that. 
  • Events are used to build a loosely couple application which classes and components are not tightly couple together. 
  • It helps to extend the application without breaking and changing the existing functionality. 
  • For an example, suppose we have a class  "VideoEncoder" which used to encode the video and send the email once video is encoded. In future, we might need to add another functionality  "send the text message" after the video is encoded. So then we have to add another functionality to send the messages. The problem is, we have to recompile the encoder class and all dependents of encoder class and redeploy. This is not a good idea. 

  • To solve this, we can use events. Here VideoEncoder is the publisher. mailService and messageService  are the subscribers. Video encoder does not know anything about the mailService and messageService. So in that case, in future if we need to add another subscriber , we can do it with minimal impact.  
       There are three main steps to implement above solution. 
  1. Define the delegate - Delegates works as a Agreement or contract between publisher and subscriber. It determines the signature of the event handler method in subscriber. 
  2. Define the Event based on that delegate.  
  3. Raise the event method which is protected ,virtual and void
    //By creating custom delegate and  EventArgs.Empty
        public class VideoEncoder
        {
            //1.Defines delegate
            //2.Defines a event based on event
            //3.raise the event
    
            public delegate void VideoEncodedEventHandler(object source, EventArgs args);
            public event VideoEncodedEventHandler VideoEncoded;
    
            public void Encode(Video video)
            {
                Console.WriteLine("Video Encoded");
                Thread.Sleep(3000);
    
                OnvideoEncoded();
            }
    
            protected virtual void OnvideoEncoded()
            {
                //VideoEncoded?.Invoke(this, EventArgs.Empty);
    
                if (VideoEncoded != null)
                {
                    VideoEncoded(this, EventArgs.Empty);
                }
    
            }
    
        }
    	
        class Program
        {
            static void Main(string[] args)
            {
                var video = new Video() { Name = "video1" };
                var videoEncoder = new VideoEncoder(); //publisher
                var mailService = new MailService();//Subscriber
                var messageService = new MessageService(); //Subscriber
    
                videoEncoder.VideoEncoded += mailService.OnVideoEncoded;
                videoEncoder.VideoEncoded += messageService.OnVideoEncoded;
                videoEncoder.Encode(video);
    	}
         }
    	
        public class MailService
        {
            public void OnVideoEncoded(object source, EventArgs args)
            {
                Console.WriteLine("Sending the email");
            }
        }
    	
    	public class MessageService
        {
            public void OnVideoEncoded(object source, EventArgs args)
            {
                Console.WriteLine("Sending the message");
            }
        }
        
        public class Video
        {
            public string Name { get; set; }
        }
    
  • Suppose we need to send addtional data (such as the video name which is encoded) to the subscriber. To do that, instead of EventsArgs we can use a custom class which derives from "EventArgs" class.
  •     //By creating custom  VideoEventArgs
        public class VideoEncoder
        {
            public delegate void VideoEncodedEventHandler(object source, VideoEventArgs args);
            public event VideoEncodedEventHandler VideoEncoded;
    
            public void Encode(Video video)
            {
                Console.WriteLine("Video Encoded");
                Thread.Sleep(3000);
    
                OnvideoEncoded(video);
            }
    
            protected virtual void OnvideoEncoded(Video video)
            {
                // VideoEncoded?.Invoke(this, new VideoEventArgs() { Video = video }); or
    
                if (VideoEncoded != null)
                {
                    VideoEncoded(this, new VideoEventArgs() { Video = video });
                }
    
            }
    
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                var video = new Video() { Name = "PickUpLimes" };
                var videoEncoder = new VideoEncoder(); //publisher
                var mailService = new MailService();//Subscriber
                var messageService = new MessageService(); //Subcriber
    
                videoEncoder.VideoEncoded += mailService.OnVideoEncoded;
                videoEncoder.VideoEncoded += messageService.OnVideoEncoded;
                videoEncoder.Encode(video);
                Console.Read();
            }
        }
    
        public class VideoEventArgs : EventArgs
        {
            public Video Video { get; set; }
        }
    
        public class MailService
        {
            public void OnVideoEncoded(object source, VideoEventArgs args)
            {
                Console.WriteLine("Sending the email. Video name is " + args.Video.Name);
            }
        }
    
        public class MessageService
        {
            public void OnVideoEncoded(object source, VideoEventArgs args)
            {
                Console.WriteLine("Sending the message. Video name is " + args.Video.Name);
            }
        }
    
        public class Video
        {
            public string Name { get; set; }
        }
    
  • In .Net , same thing can be achieved using in-built EventHandler delegate instead of creating the custom delegate. EventHandler comes in two forms. One is normal form EventHandler  and other one is generic form EventHandler<T> . If we need to pass the data, we can use generic version. If not , can use the normal form.   
  •  	
        //using EventHandler delegate instead of custom delegate
        public class VideoEncoder
        {
            //Generic Form
            public event EventHandler<VideoEventArgs> VideoEncoded;
    
            //Normal Form
           // public event EventHandler VideoEncoded; 
    
            public void Encode(Video video)
            {
                Console.WriteLine("Video Encoded");
                Thread.Sleep(3000);
    
                OnvideoEncoded(video);
            }
    
            protected virtual void OnvideoEncoded(Video video)
            {
                //VideoEncoded?.Invoke(this, EventArgs.Empty);
    
                if (VideoEncoded != null)
                {
                    VideoEncoded(this, new VideoEventArgs() { Video = video });
                }
    
            }
    
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                var video = new Video() { Name = "PickUpLimes" };
                var videoEncoder = new VideoEncoder(); //publisher
                var mailService = new MailService();//Subscriber
                var messageService = new MessageService(); //Subcriber
    
                videoEncoder.VideoEncoded += mailService.OnVideoEncoded;
                videoEncoder.VideoEncoded += messageService.OnVideoEncoded;
                videoEncoder.Encode(video);
                Console.Read();
            }
        }
    
        public class VideoEventArgs : EventArgs
        {
            public Video Video { get; set; }
        }
    
        public class MailService
        {
            public void OnVideoEncoded(object source, VideoEventArgs args)
            {
                Console.WriteLine("Sending the email. Video name is " + args.Video.Name);
            }
        }
    
        public class MessageService
        {
            public void OnVideoEncoded(object source, VideoEventArgs args)
            {
                Console.WriteLine("Sending the message. Video name is " + args.Video.Name);
            }
        }
    
        public class Video
        {
            public string Name { get; set; }
        }
    

 References : Udemy.com

No comments:

Post a Comment