In C#, a delegate defines a Type. But it is special type of
Type that references methods.
A delegate is a type safe function pointer i.e. it holds a reference(pointer)
to a function having the same signature.
In other
words, a delegate is just the memory address of a method that matches the same
signature as the delegate.
Specifically, a delegate maintains three important pieces of
information
The address of the method
on which it makes calls
The parameters (if any) of
this method
The return type (if any) of
this method
A delegate
is a reference type variable that holds the reference to a method. The
reference can be changed at runtime.
All
delegates are implicitly derived from the System.Delegate Class.
Syntax:
Delegate <return
type> <delegate-name> <Parameter list>
The
signature of the delegate must match the signature of the function the delegate
points to, otherwise we will get a compile time error. Therefore, the delegates
are called as type safe function pointers.
A delegate is similar to a class. We can create an instance
of it, and when we do so, we pass in the function name as a parameter to the
delegate constructor, and it is to this function the delegate will point to.
The syntax of delegate looks very much similar to a method
with a delegate keyword.
A delegate is reference type that basically encapsulates the
reference of methods. It is a similar to class that store the reference of
methods which have same signature as delegate has.
It is very similar to a function pointer in C++, but
delegate is type safe, object oriented and secure as compare to C++ function
pointer.
We could use delegates to create a queue of methods that
need to be called in order. Delegates have built-in support for asynchronous
operations that run on a different thread for better performance. Most
importantly, delegates allow us to create events.
An event handler signature, i.e. the return type and the
number and types of arguments it takes, is determined by the signature of the
delegate used to define the event.
A delegate instance literally acts as a delegate for the caller:
the caller invokes the delegate, and then the delegate calls the target method. This
indirection decouples the caller from the target method.
Assigning a method to a
delegate variable creates a delegate instance: eg below
delegate int
Transformer (int x);
static int Square (int
x) { return x * x; }
Transformer t = Square;
Event handlers are
connected to a control’s events via special objects called delegates.
Type
compatibility
Delegate types are all incompatible with
one another, even if their signatures are the same:
delegate void D1();
delegate void D2();
D1 d1 = Method1;
D2 d2 = d1; //
Compile-time error
The following, however, is permitted:
D2 d2 = new D2 (d1);
Delegate instances are considered equal if
they have the same method targets:
delegate void D();
...
D d1 = Method1;
D d2 = Method1;
Console.WriteLine (d1 == d2); // True
Multicast delegates are considered equal if
they reference the same methods in the same order.
Covariance
and Contravariance (ie.SubClass & BaseClass)
Covariance and contravariance give you some
flexibility when assigning methods to delegate variables. They basically let
you treat the return type and parameters of a delegate polymorphically.
Covariance lets a method
return a value from a subclass of the result expected by a delegate. For example,
suppose the Employee class is derived from the Person class and the
ReturnPersonDelegate type represents methods that return a Person object. Then
you could set a ReturnPersonDelegate variable equal to a method that returns an
Employee because Employee is a subclass of Person. This makes sense because the
method should return a Person, and an Employee is a kind of Person. (A variable
is called covariant if it enables covariance.)
Contravariance lets a
method take parameters that are from a superclass of the type expected by a
delegate. For example, suppose the EmployeeParameterDelegate type represents
methods that take an Employee object as a parameter. Then you could set an
EmployeeParameterDelegate variable equal to a method that takes a Person as a
parameter because Person is a superclass of Employee. When you invoke the
delegate variable’s method, you will pass it an Employee (because the delegate
requires that the method take an Employee parameter) and an Employee is a kind
of Person, so the method can handle it. (A variable is called contravariant if
it enables contravariance.)
When you call a method, you can supply
arguments that have more specific types than the parameters of that method. This is
ordinary polymorphic behavior. For exactly the same reason, a delegate can
have more specific parameter types than its method target.
This is called contravariance.
This is called contravariance.
Here’s an example:
delegate void StringAction (string s);
class Test
{
static void Main()
{
StringAction sa = new StringAction
(ActOnObject);
sa ("hello");
}
static void ActOnObject (object o) =>
Console.WriteLine (o); // hello
}
If you call a method, you may get back a
type that is more specific than what you asked for. This is ordinary polymorphic
behavior. For exactly the same reason, a delegate’s target method may return a more
specific type than described by the delegate.
This is called covariance.
For example:
delegate object ObjectRetriever();
class Test
{
static void Main()
{
ObjectRetriever o = new ObjectRetriever
(RetrieveString);
object result = o();
Console.WriteLine (result); // hello
}
static string RetrieveString() =>
"hello";
}
ObjectRetriever expects to get back an
object, but an object subclass will also do:
delegate return types are covariant.
Generic
delegate type parameter variance
we saw how
generic interfaces support covariant and contravariant type
parameters. The same capability exists for delegates too (from C# 4.0 onward).
If you’re
defining a generic delegate type, it’s good practice to:
• Mark a
type parameter used only on the return value as covariant (out).
• Mark any
type parameters used only on parameters as contravariant (in).
Doing so
allows conversions to work naturally by respecting inheritance relationships
between types.
The following delegate (defined in the
System namespace) has a covariant TResult:
delegate TResult Func<out TResult>();
allowing:
Func<string> x = ...;
Func<object> y = x;
The following delegate (defined in the System
namespace) has a contravariant T:
delegate void Action<in T> (T arg);
allowing:
Action<object> x = ...;
Action<string> y
= x;
The .NET Framework defines two generic delegate types that
you can use to avoid defining your own delegates in many cases:
1. Action and
2. Func.
The generic Action delegate represents a method that
returns void. Different
versions of Action take between 0 and 18 input parameters. The following code
shows the definition of the Action delegate that takes two parameters: public delegate
void Action<in T1, in T2>(T1 arg1, T2 arg2) The keyword in within the
generic parameter list indicates that the T1 and T2 type parameters are
contravariant.
The following code
shows two ways you could declare variables of that type:
// Method 1.
private delegate void
EmployeeParameterDelegate(Employee employee);
private EmployeeParameterDelegate
EmployeeParameterMethod1;
// Method 2. private
Action<Employee> EmployeeParameterMethod2;
Func Delegates
The generic Func
delegate represents a method that returns a value. As is the case with Action, different versions of
Func take between 0 and 18 input parameters.
The following code
shows the definition of the Func delegate that takes two parameters:
public delegate TResult
Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2)
The three types defined
by the generic delegate represent the types of the two parameters and the
return value.
The code in the
previous section defined a ReturnPersonDelegate type that takes no parameters and
returns a Person object.
The following code
shows two ways you could declare variables of that type:
// Method 1.
private delegate Person
ReturnPersonDelegate();
private ReturnPersonDelegate
ReturnPersonMethod1;
// Method 2. private
Func<Person> ReturnPersonMethod2;
This code’s first
statement defines the ReturnPersonDelegate type. The statement after the first
comment declares a variable of that type. The statement after the second
comment declares a com-parable variable of type Func<Person>.
Why do we use Delegate?
There are following
reason because of we use delegate.
- It is used for type safety.
- For executing multiple methods through one execution.
- It allows us to pass methods as parameter to another function
- For asynchronous programming.
- For Call back method implementation.
- It is also used when working with event based programming.
- When creating anonymous method.
- When working with lambda expression.
- They are used for plug-in our logic without having to modifying the original class or method logic. i.e. we can decouple the logic with the help of delegates.
When Do You Use Delegates?
I believe that a lot of people can
answer the "what is a delegate?" question in interviews, but are not
able to explain when to use it. No worries! Let me tell you a few important
points about delegates.
- These are used to represent or refer to one or more functions.
- These can only be used to define call-back methods.
- In order to consume a delegate, we need to create an object to delegate.
- Delegates are especially used for implementing events and the call-back methods.
How many types of Delegate in C#?
There are three types of delegates
available in C#.
- Simple/Single Delegate:
A single delegate instance
can reference more than one target method. A target method can be added to
delegate instance using += and removed using -=. The target methods are always
called in the order they were added to the delegate instance.
- Multicast Delegate
- Generic Delegate
What are the ways to create and use delegate?
There are only five steps to create and use a delegate and these are as following.- Declare a delegate type.
- Create or find a method which has same type of signature.
- Create object/instance of delegate
- Pass the reference of method with delegate instance.
- At last Invoke the delegate object.
- Action
- Func
- Predicate
When
Delegate takes reference with single method only then it is called Single
Delegate. It is used for invocation of only one reference method.
Following example has a delegate
name as "TestDelegate" with one parameter as string.using System;
namespace
EventAndDelegateExamples
{
delegate void TestDelegate(string name);
class
FunctionPointerExample
{
public void GetName(string name)
{
Console.WriteLine(
"Full Name is : " + name);
}
}
}
Below code snippet that first we
are creating a instance of TestDelegate and passing the reference of method
"objFunctionPointerExample.GetName" method with objDelegate1.FunctionPointerExample objFunctionPointerExample =
new FunctionPointerExample();
//Call GetName function using TestDelegate
TestDelegate objDelegate1 =
new TestDelegate(objFunctionPointerExample.GetName);
objDelegate1.Invoke(
"Mukesh Kumar");
To invoke the delegate, just need
to use Invoke method to pass required parameter.What is Multicast Delegate?
When
Delegate takes reference with multiple methods then it is called multicast
delegate. It is used for invocation of multiple reference methods. We can add
or remove references of multiple methods with same instance of delegate using
(+) or (-) sign respectively. It need to consider here that all methods will be
invoked in one process and that will be in sequence.
Following example has a delegate
name as "TestMultiCastDelegate" with one parameter as int.using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace
EventAndDelegateExamples
{
delegate void TestMultiCastDelegate(int a);
class
MultiCastDelegateExample
{
internal void GetSalary(int AnnualSalary)
{
Console.WriteLine(
"Monthly Salary is "+ AnnualSalary /
12);
}
internal void GetSalaryAfterDeduction(int AnnualSalary)
{
if (AnnualSalary >
12000)
{
Console.WriteLine(
"Monthly Salry after deduction is "+ ((AnnualSalary /
12) -
500));
}
else
{
Console.WriteLine(
"Monthly Salry after deduction is " +AnnualSalary /
12);
}
}
}
}
Below code snippet shows that first we are creating a instance of TestMultiCastDelegate and passing the reference of methods [GetSalary] and [GetSalaryAfterDeduction] with "objDelegate2".
MultiCastDelegateExample objMultiCastDelegateExample =
new MultiCastDelegateExample();
//Creating the instance of the delegate
TestMultiCastDelegate objDelegate2 =
null;
//Referencing the multiple methods using + sign
objDelegate2 += objMultiCastDelegateExample.GetSalary;
objDelegate2 += objMultiCastDelegateExample.GetSalaryAfterDeduction;
objDelegate2.Invoke(
60000);
Delegates are immutable, so when
you call += or -=, you’re in fact creating a new delegate instance and
assigning it to the existing variable.
All delegate types implicitly derive
from System.MulticastDelegate, which inherits from System.Delegate. C# compiles
+,-, +=, and -= operations made on a delegate to the static Combine and Remove
methods of the System.Delegate class.
How to achieve callback in Delegate?
Callback
is term where a process is going on and in between it targets some achievement
then it returns to main method. For callback, we just need to encapsulate the
method with delegate.
objCallBackMethodExample.CheckEvenEvent +=
new OnEvenNumberHandler(objCallBackMethodExample.CallBackMethod);
Let see an
example, CallBackMethodExample is a class which have a method
CallBackMethod. It will be executed when some criteria will be fulfill. public delegate void OnEvenNumberHandler(object sender, EventArgs e);
public
class
CallBackMethodExample
{
public void CallBackMethod(object sender, EventArgs e)
{
Console.WriteLine(
"Even Number has found !");
}
}
When we are going to call this
method using Delegate for callback, only need to pass this method name as a
reference.CallBackMethodExample objCallBackMethodExample =
new CallBackMethodExample();
objCallBackMethodExample.CheckEvenEvent +=
new OnEvenNumberHandler(objCallBackMethodExample.CallBackMethod);
Random random =
new Random();
for (
int i =
0; i <
6; i++)
{
var randomNumber = random.Next(
1,
10);
Console.WriteLine(randomNumber);
if (randomNumber %
2 ==
0)
{
objCallBackMethodExample.OnCheckEvenNumber();
}
}
How to achieve Async callback in Delegate
Async callback means, process will
be going on in background and return back when it
will be completed. In C#, Async
callback can be achieved using AsyncCallback
predefined delegate as following.
public delegate void AsyncCallback(IAsyncResult ar);
Kindly follow the following example to understand the Async callback. There is a class name as
CallBackMethodExample which have two method, one is TestMethod and other one is
AsyncCallBackFunction. But as we can see AsyncCallBackFunction is taking IAsyncResult
as a parameter.
public delegate void OnEvenNumberHandler(object sender, EventArgs e);
public
class
CallBackMethodExample
{
public void TestMethod(object sender, EventArgs e)
{
Console.WriteLine(
"This is simple test method");
}
public void AsynCallBackFunction(IAsyncResult asyncResult)
{
OnEvenNumberHandler del = (OnEvenNumberHandler)asyncResult.AsyncState;
del.EndInvoke(asyncResult);
Console.WriteLine(
"Wait For 5 Seconds");
Console.WriteLine(
"...");
Console.WriteLine(
"...");
Console.WriteLine(
"...");
Console.WriteLine(
"...");
System.Threading.Thread.Sleep(
5000);
Console.WriteLine(
"Async Call Back Function Completed");
}
}
When we are going to invoke the delegate, only just need to pass AsycnCallBackFunction with delegate
instance.
CallBackMethodExample objCallBackMethodExample =
new CallBackMethodExample();
OnEvenNumberHandler objDelegate3 =
new OnEvenNumberHandler(objCallBackMethodExample.TestMethod);
objDelegate3.BeginInvoke(
null, EventArgs.Empty,
new AsyncCallback(objCallBackMethodExample.AsynCallBackFunction), objDelegate3);
Console.WriteLine(
"End of Main Function");
Console.WriteLine(
"Waiting for Async Call Back Function");
---------------------------------------------
Delegates
that don’t accept any parameters can be handled using Lambdas. Eg
delegate bool
LogDelegate();
Static
void Main(string[] args)
{
LogDelegate del = ()=> {
UpdateDatabase();
WriteEventToLog();
return true;
};
bool
status= del(); //execute the delegate
}
.Net
framework provides some built in delegates. Eg.
Action<T> it accepts a single parameter and returns no
value.
Func<T,
TResult> it accepts a single parameter and returns a value of type TResult.
Public
Static void Main(string[] args)
{
Action<string> messageTarget;
If(args.Length > 1)
{
messageTarget = ShowWindowsMessage;
}
else {
messageTarget = console.writeline;
}
messageTarget(‘Invoking action’);
}
Public
static void ShowWindowsMessage(string message)
{
MessageBox.Show(message);
}
·
Action<int, int> myAction = (x,y)=>
console.writeline(x+y);
data.Processaction(2,3, myAction);
public void Processaction(int x, int y,
Action<int, int> theaction)
{
theaction(x, y);
console.writeline(action has been processed.‘’);
}
Public
Static void Main(string[] args)
{
Func<string, bool> logFunc;
If(args[0] == “EventLog”)
{
logFunc = LogToEventLog;
}
else
{
logFunc = LogToFile;
}
bool
Status = logFunc;
}
Private
static bool LogToEventLog(string message) { /* log the message*/}
Private
static bool LogToFile(string message) { /* log the message*/}
-With
Action<T> and Func<T, TResult> we don’t have to write custom
delegates.
-
Func<int, int, int> funcAddDel = (x, y)=>
x+y;
data.Process(2,3, funcAddDel);
public void Process(int, int, Func<int,int,int>
del)
{
var
result = del(x,y);
console.writeline(result);
}
A
delegate also can be thought of as an object that contains an ordered list of
methods with the same signature and return type.
- The list of methods is called the invocation list.
- When a delegate is invoked, it calls each method in its invocation list.
For static methods, a delegate object
encapsulates the method to be called. For instance methods, a delegate object
encapsulates both an instance and a method on the instance.
An interesting and useful property of a
delegate is that it does not know or care about the class of the object that it
references. Any object will do; all that matters is that the method's argument
types and return type match the delegate's. This makes delegates perfectly
suited for "anonymous" invocation.
Delegates vs. Interfaces
Delegates and interfaces are similar in that they enable the separation of specification and implementation. Multiple independent authors can produce implementations that are compatible with an interface specification. Similarly, a delegate specifies the signature of a method, and authors can write methods that are compatible with the delegate specification. When should you use interfaces, and when should you use delegates?Delegates are useful when:
- A single method is being called.
- A class may want to have multiple implementations of the method specification.
- It is desirable to allow using a static method to implement the specification.
- An event-like design pattern is desired (for more information, see the Events Tutorial).
- The caller has no need to know or obtain the object that the method is defined on.
- The provider of the implementation wants to "hand out" the implementation of the specification to only a few select components.
- Easy composition is desired.
- The specification defines a set of related methods that will be called.
- A class typically implements the specification only once.
- The caller of the interface wants to cast to or from the interface type to obtain other interfaces or classes.
Subscribers have full access to the delegate
which means they are capable of adding more subscribers or removing an existing
subscriber without that subscriber’s knowledge, which is bad. This problem is
called as Naked Delegate Exposure.
Delegates should not be exposed to the
subscribers which means if we need to encapsulate the delegate from subscribers
to avoid them to make any changes, this encapsulation is called Events.
A Delegate which
needs to be encapsulated by Event
must be of return type void and in general has two parameters, first the sender
of the event and second the arguments which need to be passed when the event is
fired.
0 comments:
Post a Comment