Every delegate base class is System.MulticastDelegate. The System.MulticastDelegate class inherits from the delegate class. Both classes are abstract classes.
.NET provides a standard constructor as follows:
Constructor for MultiCastDelegate : protected MulticastDelegate(object target, string method);
Constructor for Delegate : protected Delegate(object target, string method);
Declare Delegate: Declarion of a delegate is quite tricky, because when we declare a delegata, we inform the compiler which kind of function signature's reference could be held by the delegate.
Let's explain by following: Fig-1.0

Look at Fig-1.0
- Public is the Access modifier.
- delegate is the keyword which indicates this is delegate type.
- Return type of function signature.
- Delegate class name. (Explained below.)
- Parameter of function signature.
- Parameter of function signature.
Let's see one more example: protected delegate string DelegateReverse (string StrText) ;
It means this delegate class object can bind a function which function return type should be string with one string parameter. DelegateReverse is delegate class name.
Question: Look at Fig-1 DelegateFunction what is this? Is this is an object or name of the delegate.
Answer: This is a sealed class. Look at the following example; then we will describe.
Code sample - 1.0
using System;
using System.Collections.Generic;
using System.Text;
namespace DelegateCode
{
class DelExample
{
// Delegate declaration.
public delegate string StringOperation(string myString);
static void Main(string[] args)
{
// Create instance of class for accessing its function
DelExample objEx = new DelExample();
// create instance of Delegate Class
StringOperation Objdelegate = new StringOperation(objEx.MyOperationReverseString);
// Call delegate object and store result in appropriate variable
string result = Objdelegate("ABC DEF GHI");
// Get Type
Type Tp = Objdelegate.GetType();
// Output
Console.WriteLine("Is this Class : " + Tp.IsClass.ToString()+ "\n");
Console.WriteLine("Inherit from : " + Tp.BaseType.ToString() + "\n");
Console.WriteLine("Is Abstract : " + Tp.IsAbstract.ToString() + "\n");
Console.WriteLine("Is ByRef : " + Tp.IsByRef.ToString() + "\n");
Console.WriteLine("Is Sealed : " + Tp.IsSealed.ToString() + "\n");
Console.WriteLine("Output of Delegate : " + result+"\n");
Console.WriteLine("Output by Invoke : " + Objdelegate.Invoke("ABC DEF GHI"));
Console.Read();
}
// definition of the function MyOperationReverseString
public string MyOperationReverseString(string test)
{
char[] Spl = test.ToCharArray();
test = string.Empty;
for (int icnt = 0; icnt < Spl.Length; icnt++)
{
test = Spl[icnt] + test;
}
return test;
}
}
}
Output of this program Fig - 2.0

Consider the Fig - 2.0 output. In the above code the following line:
public delegate string StringOperation(string myString);
StringOperation is a sealed Class. This is inherited by System.MultiCastDelegate and is not abstract.
Look at the last two lines of output. We can call the delegate using the invoke method or by passing a parameter without invoke method.
How C# Compiler understands: Whenever the compiler encounters a delegate declaration like:
public delegate string StringOperation(string myString);
Then the compiler generates following code:
public sealed class StringOperation: System.MulticastDelegate
{
public StringOperation (object target, int method);
public virtual void Invoke(string myString);
public virtual IAsyncResult BeginInvoke(string myString,
AsyncCallback callback, object obj);
public virtual void EndInvoke(IAsyncResult result);
}
Look Program-1 IL-DASM view: (Fig-3.0)

You can see .ctor: void (Object ,native int) (This is similar constructor as System.MulticastDelege constructor.)
The Invoke method should have same signature of the referenced function.
Delegate cannot declare and use as field:
Code Sample - 2.0:
namespace DelegateExample
{
public delegate string MyDelegate(string myString);
interface MyCallable
{
int GetInfo();
delegate int CalcArea(int x, int y); // Error : interfaces cannot declare types
MyDelegate ObjDelegae; // Error : Interfaces cannot contain fields
}
}
Code Sample - 3.0:
public
void DispachCall(int
tStr)
{
public delegate
string
MyDelegate(string myString); // Error
}
Difference b/w Single cast and Multicast delegate:
From the developer's perspective a delegate is two types, single-cast and
multicast. Although ".NET" has provided two classes for the delegate.
Note: Singlecast delegate vs Multicast delegate does not have ny
declaration and implementation differences. This is only perspective.
When I read articles related to delegates, they say that a Multicast delegate
cannot wrap / bind a function which returns value. But I never seem like this.
-
Delegate class ( Abstract class)
-
MulticastDelegate (Abstract class inherited by Delegate class).
Every delegate in the .NET is Multicast delegate.
Then…
Question : So what is Singlecast Delegate ?
Answer : If a delegate object has only one function's reference then it's
called a single cast delegate. If a delegate object references more than one
function then it is called a MulticastDelegate.
When a delegate object refers or binds multiple function references then all
function references are stored as a linked list. All functions will be called in
sequence as they were assigned.
Example : let's say we have the delegate object ObjDel.
ObjDel binds or wraps three functions in sequence respectively; Add, Mul and
Divide. All three functions return integer type.
Let's call the delegate:
Int result = ObjDel.invoke(15,5); It will return 3.
If function wrap in sequence Add, Divide, Mul.
Result = ObjDel.invoke(15,5). It will return 75.
It always returns the value of the last function. So what about the return
values of the other functions?
Key point: If any delegate object binds or wraps 5 return type functions,
then only the 5th function will return a value; the other 4 functions cannot
return a value. So always the last function called will return a value. The
return value from the remaining 4 functions will be ignored.
Delegates Asynchronously:
Note : Simple overview for a delegate used for an asynchronous call. More
will be explained in the next article.
Recall Fig-3.0 there is IL-DASM view. A StringOperation delegate has Invoke and
BeginInvoke functions. These two functions are created by the compiler at run
time.
In C# we can achieve an asynchronous function call using a delegate.
By default every function in the C# is synchronous. But we can call a
synchronous function as asynchronous.
The Invoke method calls the target method on the current thread. But the
BeginInvoke method is called with a different thread, the common language
runtime (CLR) queues the request and returns immediately to the caller.
BeginInvoke can be called by only a single-cast delegate otherwise it gets a
runtime exception (ArgumentException) which is "The delegate must have only one
target".
About BeginInvoke:
.NET implements the BeginInvoke function for each delegate class. So whenever
the compiler encounters a delegate declaration it implements three methods for
each delegate class.
Invoke, BeginInvoke and EndInvoke. Each BeginInvoke has a corresponding
EndInvoke.
Key point: Always call EndInvoke to complete your asynchronous call; it
does not matter what the technique used for calling it.
BeginInvoke has three parameters. BeginInvoke returns an IAsyncresult.
|
S.No |
|
Description |
|
1. |
parameters of the function which calling |
|
|
2. |
AsynchCallback |
.
|
|
3. |
System.Object |
|
Signature of the BeginInvoke method's second parameter is:
AsyncCallback (IAsyncResult Ar).
Key Point: IAsyncresult is used for monitoring and providing the state or
progress of the asynchronous function call.
This is returned by BeginInvoke and
it is also a parameter for the AsyncCallback function. Its declaration is:
public interface IAsyncResult
{
object AsyncState{ get; }
WaitHandle AsyncWaitHandle { get; }
bool CompletedSynchronously { get; }
bool IsCompleted { get; }
}
Key Point: Call delegate using Invoke method. Then it's run in the same
thread.
Look at the following simple code. I called the same delegate using the Invoke
and BeginInvoke methods. And write thread ID for both calls.
Code Sample - 4.0:
using
System;
using
System.Threading;
namespace
TestMultipuleDelegate
{
class
MultiCastTest : TestMultipuleDelegate.IMultiCastTest
{
delegate int
Calc(int
x, int y,out
int id);
static void Main(string[]
args)
{
int thid = 0;
MultiCastTest ClObj =
new
MultiCastTest();
Calc objCalc =
new
Calc(ClObj.Add);
// Get current thread ID
thid = AppDomain.GetCurrentThreadId();
Console.WriteLine("
");
Console.WriteLine("
Main Application Thread ID : " + thid.ToString());
Console.WriteLine();
// Call delegate by Invoke method (synchronous call
int Result = objCalc.Invoke(8, 8,
out thid);
Console.WriteLine("Invoke method completed "); Console.WriteLine();
// Call delegate by BeginInvoke : Asynchronous call
IAsyncResult rs =
objCalc.BeginInvoke(234, 6, out thid,
null,null);
Console.WriteLine("Begin
Invoke has been start."); Console.WriteLine();
// Calling continue Mul funtion along Main thread.
Console.WriteLine(
"Resule Mul " + ClObj.Mul(10, 8).ToString());
// Waiting till completed the Asynchronous call
completed.
while (rs.IsCompleted ==
false)
{
Console.WriteLine("On
processing..."); Console.WriteLine();
Thread.Sleep(1000);
}
//// Get the result of Asynchronous ,calling
functions
Result = objCalc.EndInvoke(out thid,rs);
Console.WriteLine("Result
: " + Result.ToString()); Console.WriteLine();
Console.WriteLine("Process
completed"); Console.WriteLine();
Console.ReadKey();
}
public int Add(int
x, int y,out
int thid)
{
Console.WriteLine("In
side Calling function Add : ");
Console.WriteLine();
// Get calling function thread ID
thid = AppDomain.GetCurrentThreadId();
Console.WriteLine("
Calling function Thread ID : " + thid.ToString());
Console.WriteLine();
Thread.Sleep(1000);
return x + y;
}
public int Mul(int
a, int b)
{
Console.WriteLine("Inside
Multipule function thred ID. "+
AppDomain.GetCurrentThreadId().ToString());
Console.WriteLine();
return a*b;
}
}
}
// another .CS
file
using System;
namespace
TestMultipuleDelegate
{
interface
IMultiCastTest
{
int Add(int
x, int y, out
int thid);
int Mul(int
a, int b);
}
}
Fig - 4.0 ( Code Sample - 4.0 outputs)

We can see at Fig-4.0: (Code Sample - 4.0 outputs)
Main thread id = Invoke method function call thread id = simple function call
immediate after BeginInvoke function call. But the BeginInvoke function call
thread id is 2992, which is different.
Some facts about delegates:
-
Delegate is object and by default private type access modifier.
-
Delegate class generated by C# compiler according to its declaration.
-
Delegate class object can hold reference of static or any class object's function.
-
Delegate class is a sealed class generated by the C# compiler during run time.
-
Delegate is keyword so any function cannot return delegate type.
-
Delegate cannot be used as a field of the class.
-
Delegate provides asynchronous and synchronous call.

Harshit GuptaPosted Jul 23, 2019, 6:28 AM
very good article learns alot from this article
Parvez AhadPosted Jul 14, 2016, 1:49 AM
Good Article
Harendra RajputPosted Jul 19, 2011, 1:32 AM
Good Article
jamshed alameditedPosted Jul 18, 2011, 3:40 AMEdited Jul 18, 2011, 4:02 AM
It's really great work that explain so important and tricky topics of c# delegate so easily and simple manner. I hearty congratulate rajesh bisht and would like to request to keep publishing such kind of article....
Tom LewisPosted Jul 17, 2011, 3:24 PM
Great Article!
Dinesh BeniwalPosted Jul 17, 2011, 12:27 PM
Best article on delegate, Welcome to the Mindcracker Community.
LanaPosted Jul 17, 2011, 10:45 AM
thanks for sharing