Understanding Delegates In C#

event

What is Event

Events are signal for action/notification and a mechanism to communicate between objects. The object raises the event but it doesn’t explicitly require to know the object that will handle the event. Events can help us to create a loosely coupled application. We can also use the events for extending the application.

The object that raises the event do not need to explicitly know the object that will handle the event. EventArgs is passed by event which is also known as event data.

Event handler is responsible for receiving and processing data from a delegate. Eventargs is responsible for encapsulating event data.

What is Delegate

A delegate in C# is similar to a function pointer of C or C++. It is a type that references methods. We can also say that a delegate is the pipeline between an event and event handler.

Let’s try to understand it with an example,

Sending email to all users and writing message on Console with the use of delegate

  1. namespace DelegateExample  
  2. {  
  3.     publicclassProgram  
  4.     {  
  5.         publicdelegatevoidMyCustomDelegate();  
  6.         publicstaticvoid Main(string[] args)  
  7.         {  
  8.             MyCustomDelegate myCustomDelegate = newMyCustomDelegate(SendMailtoAllGoldMembers);  
  9.             myCustomDelegate.Invoke();  
  10.         }  
  11.   
  12.         publicstaticvoid SendMailtoAllGoldMembers()  
  13.         {  
  14.             foreach(var emailId in GetListofEmailIdForGoldMembers())  
  15.             {  
  16.                 //logic for sending the mail to all the gold members  
  17.                 System.Threading.Thread.Sleep(2000); //assuming that it will take 2 seconds to send a mail.  
  18.                 Console.WriteLine($ "Email Id {emailId} : mail sent");  
  19.             }  
  20.         }  
  21.   
  22.         publicstaticList < string > GetListofEmailIdForGoldMembers()  
  23.         {  
  24.             List < string > ListOfEmailIds = newList < string > ();  
  25.             for (int i = 1; i <= 100; i++)   
  26.             {  
  27.                 ListOfEmailIds.Add($ "member{i.ToString("  
  28.                     D4 ")}@gmail.com");  
  29.             }  
  30.   
  31.             return ListOfEmailIds;  
  32.         }  
  33.   
  34.     }  
  35. }  
output

But you may ask the question that why we need to use the delegate, since we can call the method SendMailtoAllGoldMembers() directly. Yes we can also write it as follows:

Sending email to all users and writing message on Console window without using any delegate
  1. publicclassProgram   
  2. {  
  3.     publicstaticvoid Main(string[] args)   
  4.     {  
  5.         SendMailtoAllGoldMembers();  
  6.     }  
  7.   
  8.     publicstaticvoid SendMailtoAllGoldMembers()   
  9.     {  
  10.         foreach(var emailId in GetListofEmailIdForGoldMembers())   
  11.         {  
  12.             //logic for sending the mail to all the gold members  
  13.             System.Threading.Thread.Sleep(2000); //assuming that it will take 2 seconds to send a mail.  
  14.             Console.WriteLine($ "Email Id {emailId} : mail sent");  
  15.         }  
  16.     }  
  17.   
  18.     publicstaticList < string > GetListofEmailIdForGoldMembers()   
  19.     {  
  20.         List < string > ListOfEmailIds = newList < string > ();  
  21.         for (int i = 1; i <= 100; i++)   
  22.         {  
  23.             ListOfEmailIds.Add($ "member{i.ToString("  
  24.                 D4 ")}@gmail.com");  
  25.         }  
  26.   
  27.         return ListOfEmailIds;  
  28.     }  
  29.   
  30. }  
But in the above program you can see that it is tightly coupled &SendMailtoAllGoldMembers() is doing the task of writing on console window.

Writing message in log file rather than Console Window

Now suppose my requirement has been changed and I want to write all these messages in log file rather than displaying it on console window.

So you can write the program like below:
  1. publicstaticvoid Main(string[] args)   
  2. {  
  3.     SendMailtoAllGoldMembers();  
  4. }  
  5.   
  6.   
  7. publicstaticvoid SendMailtoAllGoldMembers()   
  8. {  
  9.     foreach(var emailId in GetListofEmailIdForGoldMembers())   
  10.     {  
  11.         //logic for sending the mail to all the gold members  
  12.         System.Threading.Thread.Sleep(2000); //assuming that it will take 2 seconds to send a mail.  
  13.         //Console.WriteLine($"Email Id {emailId} : mail sent");  
  14.         System.IO.File.AppendAllText(@ "D:\\delexample\log.txt", $ "\n Email Id {emailId} : mail sent");  
  15.     }  
  16. }  
log

Writing message in database table rather than log file

Suppose again requirement changes and I need to insert the email sent status into a database table again I need to change it.
  1. publicstaticvoid SendMailtoAllGoldMembers()   
  2. {  
  3.     foreach(var emailId in GetListofEmailIdForGoldMembers())   
  4.     {  
  5.         //logic for sending the mail to all the gold members  
  6.         System.Threading.Thread.Sleep(2000); //assuming that it will take 2 seconds to send a mail.  
  7.         //Console.WriteLine($"Email Id {emailId} : mail sent");  
  8.         //System.IO.File.AppendAllText(@"D:\\delexample\log.txt", $"\n Email Id {emailId} : mail sent");  
  9.         InsertTheLogDetailsIntoDatabase($ "Email Id {emailId} : mail sent");  
  10.     }  
  11. }  
Handling all the above scenarios with delegate

Let us see how I can handle it using  delegate,
  1. Create a delegate that accept string as argument
    1. publicdelegatevoidEmailSentNotificationDelegate(string notificationMsg);  
  2. Create a method to send the email messages
    1. publicstaticvoid SendMailtoAllGoldMembers(EmailSentNotificationDelegate EmailSentNotification)   
    2. {  
    3.     foreach(var emailId in GetListofEmailIdForGoldMembers())   
    4.     {  
    5.         //logic for sending the mail to all the gold members  
    6.         System.Threading.Thread.Sleep(2000); //assuming that it will take 2 seconds to send a mail.   
    7.         EmailSentNotification($ "Email Id {emailId} : mail sent");  
    8.   
    9.     }  
    10. }  
  3. Create a method for writing log in console window
    1. publicstaticvoid WriteEmailSentNotificationOnConsole(string notificationMsg)  
    2. {  
    3.     Console.WriteLine(notificationMsg);  
    4. }  
  4. Create a method to write log in log file
    1. publicstaticvoid WriteEmailSentNotificationinLogFile(string notificationMsg)   
    2. {  
    3.     System.IO.File.AppendAllText(@ "D:\\delexample\log.txt", $ "\n {notificationMsg}");  
    4. }  
  5. Create a method to write log in database
    1. publicstaticvoid WriteEmailSentNotificationinDatabase(string notificationMsg)  
    2. {  
    3.     InsertTheLogDetailsIntoDatabase(notificationMsg);  
    4. }  
  6. Calling the SendMailtoAllGoldMembers method

    a. Calling SendMailtoAllGoldMembersmethod and writing log in console window,
    1. SendMailtoAllGoldMembers(WriteEmailSentNotificationOnConsole);  
    b. Calling SendMailtoAllGoldMembers method and writing log in log file,
    1. SendMailtoAllGoldMembers(WriteEmailSentNotificationinLogFile);  
    c. Calling SendMailtoAllGoldMembers method and writing log in database,
    1. SendMailtoAllGoldMembers(WriteEmailSentNotificationinDatabase);  

Complete code

  1. publicclassProgram   
  2. {  
  3.     publicdelegatevoidEmailSentNotificationDelegate(string notificationMsg);  
  4.     publicstaticvoid Main(string[] args)   
  5.     {  
  6.         SendMailtoAllGoldMembers(WriteEmailSentNotificationOnConsole);  
  7.         //SendMailtoAllGoldMembers(WriteEmailSentNotificationinLogFile);  
  8.         //SendMailtoAllGoldMembers(WriteEmailSentNotificationinDatabase);  
  9.     }  
  10.   
  11.     publicstaticvoid SendMailtoAllGoldMembers(EmailSentNotificationDelegate EmailSentNotification)   
  12.     {  
  13.         foreach(var emailId in GetListofEmailIdForGoldMembers())   
  14.         {  
  15.             //logic for sending the mail to all the gold members  
  16.             System.Threading.Thread.Sleep(2000); //assuming that it will take 2 seconds to send a mail.   
  17.             EmailSentNotification($ "Email Id {emailId} : mail sent");  
  18.   
  19.         }  
  20.     }  
  21.   
  22.     privatestaticvoid InsertTheLogDetailsIntoDatabase(string msg)   
  23.     {  
  24.         //logic to insert notification in database table  
  25.     }  
  26.   
  27.     publicstaticList < string > GetListofEmailIdForGoldMembers()   
  28.     {  
  29.         List < string > ListOfEmailIds = newList < string > ();  
  30.         for (int i = 1; i <= 100; i++) {  
  31.             ListOfEmailIds.Add($ "member{i.ToString("  
  32.                 D4 ")}@gmail.com");  
  33.         }  
  34.   
  35.         return ListOfEmailIds;  
  36.     }  
  37.   
  38.     publicstaticvoid WriteEmailSentNotificationOnConsole(string notificationMsg)   
  39.       
  40.         Console.WriteLine(notificationMsg);  
  41.     }  
  42.   
  43.   
  44.     publicstaticvoid WriteEmailSentNotificationinLogFile(string notificationMsg)   
  45.     {  
  46.         System.IO.File.AppendAllText(@ "D:\\delexample\log.txt", $ "\n {notificationMsg}");  
  47.     }  
  48.     publicstaticvoid WriteEmailSentNotificationinDatabase(string notificationMsg)   
  49.      {  
  50.         InsertTheLogDetailsIntoDatabase(notificationMsg);  
  51.     }  
  52.   
  53. }  
We can represent the whole logic using the following screenshot.

mails

So this is the way to create custom delegate in C# but you may be thinking that where .NET Framework use the delegate or what are the in-built delegate used for event handling.

Delegates &Event Handling with Windows Form Application

I am creating a simple windows application.

In Form1.Designer.cs the code snippet is,
  1. //   
  2. // button1  
  3. //   
  4. this.button1.Location = new System.Drawing.Point(37, 26);  
  5. this.button1.Name = "button1";  
  6. this.button1.Size = new System.Drawing.Size(75, 23);  
  7. this.button1.TabIndex = 0;  
  8. this.button1.Text = "button1";  
  9. this.button1.UseVisualStyleBackColor = true;  
  10. this.button1.Click += new System.EventHandler(this.button1_Click);  
And code snippet for Form1.cs is,
  1. privatevoid button1_Click(object sender, EventArgs e)   
  2. {  
  3.   
  4. }  
So you can see System.EventHandler is a delegate which is associating button1_Click method with button1 click event.

If you press F12 (go to definition) on EventHandler then you will find the following code snippet.
  1. namespace System  
  2. {  
  3. //  
  4. // Summary:  
  5. // Represents the method that will handle an event that has no event data.  
  6. //  
  7. // Parameters:  
  8. // sender:  
  9. // The source of the event.  
  10. //  
  11. // e:  
  12. // An object that contains no event data.  
  13. [ComVisible(true)]  
  14. publicdelegatevoidEventHandler(object sender, EventArgs e);  
  15. }  
Delegates & Event Handling with WPF Application

Now I am creating a WPF application

MainWindow.xaml
  1. <Button x:Name="button" Content="Button" HorizontalAlignment="Left" Margin="78,49,0,0" VerticalAlignment="Top" Width="154" Height="54" Click="button_Click"/>  
MainWindow.g.i.cs
  1. this.button.Click += new System.Windows.RoutedEventHandler(this.button_Click);  
MainWindow.xaml.cs
  1. privatevoid button_Click(object sender, RoutedEventArgs e)  
  2. {  
  3.   
  4. }  
In the above example you can see RoutedEventHandler is a delegate, Now press F12 (go to definition) for RoutedEventHandler. You will find the following definition,
  1. namespace System.Windows  
  2. {  
  3. //  
  4. // Summary:  
  5. // Represents the method that will handle various routed events that do not have  
  6. // specific event data beyond the data that is common for all routed events.  
  7. //  
  8. // Parameters:  
  9. // sender:  
  10. // The object where the event handler is attached.  
  11. //  
  12. // e:  
  13. // The event data.  
  14. publicdelegatevoidRoutedEventHandler(object sender, RoutedEventArgs e);  
  15. }  
Delegates &Event Handling with ASP.NET Web Form

Now create an ASP.NET web Form application.

On .aspx page the following code snippet is written
  1. <formid="form1" runat="server">  
  2.     <div>  
  3.   
  4.         <asp:ButtonID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />  
  5.   
  6.     </div>  
  7.  </form>  
And on .cs file the following code snippet is written
  1. protectedvoid Button1_Click(object sender, EventArgs e)   
  2. {  
  3.     //do something  
  4. }  
Here Button1_Click written with OnClick="Button1_Click" is delegate but you may be thinking that where the delegate is calling the method. Actually it is happening behind the scene. This is a syntactic sugar of ASP.NET web form.

Till now we have created only simple delegate let’s deep dive into it and use the custom delegate in more detail.

As we know delegate keyword is used to define custom delegate, there are 2 types of delegates,
  1. Single cast delegate
  2. Multicast delegate

Multicast delegate

A multicast delegate can reference more than one delegate function. It tracks delegate references using an invocation list and all the delegates in the list invoked sequentially.

We can take above example for multiple invocation list.

Code

  1. publicstaticvoid Main(string[] args)   
  2. {  
  3.     EmailSentNotificationHandler del1 = newEmailSentNotificationHandler(WriteEmailSentNotificationOnConsole);  
  4.     del1 += WriteEmailSentNotificationinLogFile;  
  5.     del1 += WriteEmailSentNotificationinDatabase;  
  6.     SendMailtoAllGoldMembers(del1);  
  7. }  
The rest part of the code will be the same.

Now I can write log in a log file and display log message on console window and also data is being inserted in database. So I am doing all the 3 logging work.

As delegate provide the functionality to add & remove delegate any time so we can unsubscribe it any time

Example:
  1. publicstaticvoid Main(string[] args)   
  2. {  
  3.   
  4.     EmailSentNotificationHandler del1 = newEmailSentNotificationHandler(WriteEmailSentNotificationOnConsole);  
  5.     del1 += WriteEmailSentNotificationinLogFile;  
  6.     del1 += WriteEmailSentNotificationinDatabase;  
  7.     SendMailtoAllGoldMembers(del1);  
  8. }  
  9. publicstaticvoid SendMailtoAllGoldMembers(EmailSentNotificationHandler EmailSentNotification)  
  10. {  
  11.     foreach(var emailId in GetListofEmailIdForGoldMembers())  
  12.     {  
  13.         //logic for sending the mail to all the gold members  
  14.         System.Threading.Thread.Sleep(2000); //assuming that it will take 2 seconds to send a mail.   
  15.         EmailSentNotification -= WriteEmailSentNotificationinDatabase;  
  16.         EmailSentNotification -= WriteEmailSentNotificationinLogFile;  
  17.         EmailSentNotification($ "Email Id {emailId} : mail sent");  
  18.     }  
  19. }  
So in the above code I have removed WriteEmailSentNotificationinDatabase & WriteEmailSentNotificationinLogFile inside SendMailtoAllGoldMembers() method so now it will write message only on console window.

Delegate cannot be called like a method

We cannot call a delegate directly like a method; if we try to call it will throw the exception e.g. if I write

EmailSentNotificationHandler($"Email Id {emailId} : mail sent");

It will give the compile time error

Non-invocable member 'Program.EmailSentNotificationHandler' cannot be used like a method.

Calling a delegate using Invoke method
  1. publicstaticvoid Main(string[] args)   
  2. {  
  3.     EmailSentNotificationHandler del1 = newEmailSentNotificationHandler(WriteEmailSentNotificationOnConsole);  
  4.     del1 += WriteEmailSentNotificationinLogFile;  
  5.     del1 += WriteEmailSentNotificationinDatabase;  
  6.     del1.Invoke($ "Email Id {emailId} : mail sent");  
  7. }  
Calling a delegate by passing it as parameter
  1. publicstaticvoid Main(string[] args)  
  2. {  
  3.     EmailSentNotificationHandler del1 = newEmailSentNotificationHandler(WriteEmailSentNotificationOnConsole);  
  4.     del1 += WriteEmailSentNotificationinLogFile;  
  5.     del1 += WriteEmailSentNotificationinDatabase;  
  6.     SendMailtoAllGoldMembers(del1);  
  7.   
  8. }  
Calling a delegate by passing parameters inside the delegate object.

We can also call the delegate by passing parameters inside the delegate object
Example:
  1. publicdelegatevoidLogger(string message);  
  2. Logger log = newLogger(WriteMsgOnConsole);  
  3. log("Transaction completed successfully");  
Complete code
  1. classProgram   
  2. {  
  3.     publicdelegatevoidLogger(string message);  
  4.     staticvoid Main(string[] args)  
  5.     {  
  6.         Logger log = newLogger(WriteMsgOnConsole);  
  7.         log("Transaction completed successfully");  
  8.     }  
  9.   
  10.     publicstaticvoidWriteMsgOnConsole(string message)   
  11.     {  
  12.         Console.WriteLine(message);  
  13.     }  
  14. }  
You may have noticed that I am using a lot of static method while explaining the delegate but it’s not mandatory that a method should be static. I am using static method just for my convenience.

We can also write the above example without using the static method.
  1. classLogging   
  2. {  
  3.     publicdelegatevoidLogger(string message);  
  4.     staticvoid Main(string[] args)   
  5.     {  
  6.         Logging logging = newLogging();  
  7.         Logger log = newLogger(logging.WriteMsgOnConsole);  
  8.         log("Transaction completed successfully");  
  9.     }  
  10.   
  11.     publicvoid WriteMsgOnConsole(string message)   
  12.     {  
  13.         Console.WriteLine(message);  
  14.     }  
  15. }  
For using delegate name of the method and name of the delegate doesn’t matter only the thing that matter is return type & parameter type of the method should be same as that of delegate.

I would like to clarify that all the delegates in C# is by default multicast delegate. I am listening from many years that multicast delegate must have return type void but I do not agree with this statement. I have used multicast delegate that is not having the return type as void but it is not throwing any exception.

Using int(System.Int32) Type Multicast delegate

Multicast delegate can reference more than one delegate function and it tracks the delegate references using an invocation list.

You may be thinking that if you are referencing more than 1 delegate function then how it will be executed and what will be the sequence for it. It will be executed one by one and invoked sequentially in the same order in which it has been added.

Let’s try to understand it with an example:

Create a delegate which accept 2 int parameters and return an int value

public delegate int SomeActionPerformedHandler(int x, int y);

Create 4 different methods each of them will accept 2 int parameters and return an int value
  1. public static int FirstWorkPerformed(int x, int y)   
  2. {  
  3.     //do something for FirstWorkPerformed  
  4.     System.Threading.Thread.Sleep(500);  
  5.     Console.WriteLine("FirstWorkPerformed Executed");  
  6.     return 10; //I am returning different value so that you can easily differentiate that which value has been returned.  
  7. }  
  8.   
  9. public static int SecondWorkPerformed(int x, int y)   
  10. {  
  11.     //do something for SecondWorkPerformed  
  12.     System.Threading.Thread.Sleep(500);  
  13.     Console.WriteLine("SecondWorkPerformed Executed");  
  14.     return 20; //I am returning different value so that you can easily differentiate that which value has been returned.  
  15. }  
  16.   
  17. public static int ThirdWorkPerformed(int x, int y)   
  18. {  
  19.     //do something for ThirdWorkPerformed  
  20.     System.Threading.Thread.Sleep(500);  
  21.     Console.WriteLine("ThirdWorkPerformed Executed");  
  22.     return 30; //I am returning different value so that you can easily differentiate that which value has been returned.  
  23. }  
  24.   
  25. public static int FourthWorkPerformed(int x, int y)  
  26. {  
  27.     //do something for FourthWorkPerformed  
  28.     System.Threading.Thread.Sleep(500);  
  29.     Console.WriteLine("FourthWorkPerformed Executed");  
  30.     return 40; //I am returning different value so that you can easily differentiate that which value has been returned.  
  31. }  
Adding all the methods in invocation list and calling it.
  1. SomeActionPerformedHandler mycustomdelegate1 = newSomeActionPerformedHandler(FirstWorkPerformed);  
  2. SomeActionPerformedHandler mycustomdelegate2 = newSomeActionPerformedHandler(SecondWorkPerformed);  
  3. SomeActionPerformedHandler mycustomdelegate3 = newSomeActionPerformedHandler(ThirdWorkPerformed);  
  4. SomeActionPerformedHandler mycustomdelegate4 = newSomeActionPerformedHandler(FourthWorkPerformed);  
  5.   
  6. mycustomdelegate1 += mycustomdelegate2;  
  7. mycustomdelegate1 += mycustomdelegate3;  
  8. mycustomdelegate1 += mycustomdelegate4;  
  9.   
  10. //or   
  11. //mycustomdelegate1 += mycustomdelegate2 + mycustomdelegate3 + mycustomdelegate4;  
  12.   
  13. int delegateRuturbedValue = mycustomdelegate1(10, 20);  
Complete code
  1. classProgram  
  2. {  
  3.     publicdelegateintSomeActionPerformedHandler(int x, int y);  
  4.     staticvoid Main(string[] args)   
  5.     {  
  6.         //Adding to Invocation list  
  7.         SomeActionPerformedHandler mycustomdelegate1 = newSomeActionPerformedHandler(FirstWorkPerformed);  
  8.         SomeActionPerformedHandler mycustomdelegate2 = newSomeActionPerformedHandler(SecondWorkPerformed);  
  9.         SomeActionPerformedHandler mycustomdelegate3 = newSomeActionPerformedHandler(ThirdWorkPerformed);  
  10.         SomeActionPerformedHandler mycustomdelegate4 = newSomeActionPerformedHandler(FourthWorkPerformed);  
  11.   
  12.         mycustomdelegate1 += mycustomdelegate2;  
  13.         mycustomdelegate1 += mycustomdelegate3;  
  14.         mycustomdelegate1 += mycustomdelegate4;  
  15.   
  16.         //or   
  17.         //mycustomdelegate1 += mycustomdelegate2 + mycustomdelegate3 + mycustomdelegate4;  
  18.   
  19.         intdelegateRuturbedValue = mycustomdelegate1(10, 20);  
  20.         Console.WriteLine($ "returned value from the delegate is: {delegateRuturbedValue}");  
  21.         Console.ReadKey();  
  22.   
  23.     }  
  24.     publicstaticintFirstWorkPerformed(int x, int y)  
  25.     {  
  26.         //do something for FirstWorkPerformed  
  27.         System.Threading.Thread.Sleep(500);  
  28.         Console.WriteLine("FirstWorkPerformed Executed");  
  29.         return 10; //I am returning different value so that you can easily differentiate that which value has been returned.  
  30.     }  
  31.   
  32.     publicstaticintSecondWorkPerformed(int x, int y)   
  33.     {  
  34.         //do something for SecondWorkPerformed  
  35.         System.Threading.Thread.Sleep(500);  
  36.         Console.WriteLine("SecondWorkPerformed Executed");  
  37.         return 20; //I am returning different value so that you can easily differentiate that which value has been returned.  
  38.     }  
  39.   
  40.     publicstaticintThirdWorkPerformed(int x, int y)   
  41.     {  
  42.         //do something for ThirdWorkPerformed  
  43.         System.Threading.Thread.Sleep(500);  
  44.         Console.WriteLine("ThirdWorkPerformed Executed");  
  45.         return 30; //I am returning different value so that you can easily differentiate that which value has been returned.  
  46.     }  
  47.   
  48.     publicstaticintFourthWorkPerformed(int x, int y)   
  49.     {  
  50.         //do something for FourthWorkPerformed  
  51.         System.Threading.Thread.Sleep(500);  
  52.         Console.WriteLine("FourthWorkPerformed Executed");  
  53.         return 40; //I am returning different value so that you can easily differentiate that which value has been returned.  
  54.     }  
  55. }  
Output

output

So you can see the output screen of console it is a proof for the following statements:
  1. All the methods executed in the same order in which delegate references has been added.
  2. In case of multicast delegate only the value returned from the last delegate reference.
  3. It’s not mandatory to use void type for multicast delegate we can use other return type also with multicast delegate. And it is not throwing any exception.

So till now you have learnt that for multicast delegate we must delegate with same return type and same number of parameter.

But suppose you are an interviewee and interviewer ask that can I use default parameter with delegates? Let’s try it and see the result.

I have changed the 2nd parameter as default parameter,

  1. publicstaticintFirstWorkPerformed(int x, int y = 0)  
  2. {  
  3.     //do something for FirstWorkPerformed  
  4.     System.Threading.Thread.Sleep(500);  
  5.     Console.WriteLine("FirstWorkPerformed Executed");  
  6.     return 10; //I am returning different value so that you can easily differentiate that which value has been returned.  
  7. }  
And it works.

Now change the 2nd parameter of delegate and pass some default value,
  1. publicdelegateintSomeActionPerformedHandler(int x, int y=0);  
It also works, Now add 3rd parameter for method FirstWorkPerformed.

e.g.
  1. publicstaticintFirstWorkPerformed(int x, int y, int z = 0)  
  2. {  
  3.     //do something for FirstWorkPerformed  
  4.     System.Threading.Thread.Sleep(500);  
  5.     Console.WriteLine("FirstWorkPerformed Executed");  
  6.     return 10; //I am returning different value so that you can easily differentiate that which value has been returned.  
  7. }  
Then it will give error while adding the method reference in delegate,

refrence

I was just giving a twist that while facing an interview an interviewer may ask such type of question.

Removing from Invocation list,
  1. //Removing from Invocation list  
  2. mycustomdelegate1 -= mycustomdelegate2;  
  3. mycustomdelegate1 -= mycustomdelegate3;  
  4. mycustomdelegate1 -= mycustomdelegate4;  
But as we know that C# is more than 15 year old language and since that a lot of improvement has been done in C#.

Whatever the concept I have explained in this article is being used from C# 1.0 but later on a lot of changes has been happened in C#.

Before C# 2.0 we used to call delegate with named method but later on in C# 2.0 Microsoft introduced a new feature for calling delegate known as anonymous method and later on in C# 3.0 it also introduced lambda expression.

Later on some other in-built delegate has been introduced,

Delegate, Action,Action<T>, Action<T1, T2>>, Action<T1, T2, T3>, Action<T1, T2, T3, T4>, AppDomainInitializer, AssemblyLoadEventHandler, AsyncCallback, Comparison<T>, ConsoleCancelEventHandler, CrossAppDomainDelegate, EventHandler, EventHandler<TEventArgs>,
Func<TResult> , Func<T, TResult>

,Func<T1, T2, TResult> , Func<T1, T2, T3, TResult> ,Func<T1, T2, T3, T4, TResult> ,Predicate<T>, ResolveEventHandler, UnhandledExceptionEventHandler etc.

But I am not going to explain those things in this article because it will be mix up and confuse. I will explain Anonymous method, Lambda expression and in-built delegates in next article.