Why Delegates?
Delegates are used in the following cases:
- Delegates can be used to handle(call/invoke) multiple methods on a single event.
- Delegates can be used to define callback(asynchronous) methods.
- Delegates can be used for decoupling and implementing generic behaviors.
- Delegates can be invoked method at runtime.
- Delegates can be used in LINQ for parsing the
ExpressionTree
. - Delegates can be used in different Design Pattern.
Definition
A delegate(known as function pointer in C/C++) is a references type that invokes single/multiple method(s) through the delegate instance. It holds a reference of the methods. Delegate types are sealed and immutable type.
Types of Delegates
There are three types of delegates that can be used in C#.
- Single Delegate
- Multicast Delegate
- Generic Delegate
Single Delegate
Single delegate can be used to invoke a single method. In the given source code example, a delegate
CalculateSimpleInterest
invokes a method getTotalInterest()
.
Hide Shrink Copy Code
/// Sample example of simple delegate
///
class Program
{
// Declare a delegate
delegate double CalculateSimpleInterest(double p, double t, double r);
static CalculateSimpleInterest SI = getTotalInterest;
static void Main(string[] args)
{
double totalInterest;
//Method I : Invocation of simple delegate by using Invoke keyword
totalInterest = SI.Invoke(120, 1, 3.25);
Console.WriteLine("Total Interest of $120
in a year at rate of 3.25% APR is {0}",totalInterest);
//Method II : Invocation of simple delegate by passing method name
CalculateSimpleInterest D = new CalculateSimpleInterest(getTotalInterest);
totalInterest = D(120, 1, 3.25);
Console.WriteLine("Total Interest of $120
in a year at rate of 3.25% APR is {0}", totalInterest);
Console.ReadKey();
}
//Creating methods which will be assigned to delegate object
/// <summary>
/// Gets the total interest.
/// </summary>
/// <param name="p" />The Principal.
/// <param name="t" />The Time.
/// <param name="r" />The Rate.
/// <returns>Total Interest
static double getTotalInterest(double p, double t, double r)
{
return (p * t * r) / 100;
}
}
Multicast Delegate
Multicast delegate can be used to invoke the multiple methods. The delegate instance can do multicasting (adding new method on existing delegate instance) using the + operator and – operator can be used to remove a method from a delegate instance. All methods will invoke in sequence as they are assigned.
In the given source code example, a delegate instance
dObjSI
invokes the methods getTotalInterest()
, getInterestRatePerYear()
and getInterestTimeSpan()
.
Hide Shrink Copy Code
/// <summary>
/// Sample example of multicast delegate
///
class Program
{
// Declare a delegate
delegate double CalculateSimpleInterest(double para1, double para2, double para3);
static CalculateSimpleInterest dObjSI = getTotalInterest;
static void Main(string[] args)
{
double SI;
//Calculating simple interest
SI = dObjSI.Invoke(120, 1, 3.25);
//using multicast delegate by invoking method getInterestRatePerYear()
dObjSI += new CalculateSimpleInterest(getInterestRatePerYear);
double Rate=dObjSI.Invoke(SI, 120, 1);
Console.WriteLine("APR rate is {0}", Rate);
//using multicast delegate by invoking method getInterestTimeSpan()
dObjSI += new CalculateSimpleInterest(getInterestTimeSpan);
double TimeSpan = dObjSI.Invoke(SI, 120, 3.25);
Console.WriteLine("Time Span is {0}", TimeSpan);
Console.ReadKey();
}
/// <summary>
/// Gets the total interest.
/// </summary>
/// <param name="p" />The Principal.
/// <param name="t" />The Time.
/// <param name="r" />The Rate.
/// <returns>Total Interest
static double getTotalInterest(double p, double t, double r)
{
return (p * t * r) / 100;
}
/// <summary>
/// Gets the interest rate per year.
/// </summary>
/// <param name="SI" />The Simple Interest.
/// <param name="p" />The Principal.
/// <param name="t" />The Time.
/// <returns>Interest rate per year
static double getInterestRatePerYear(double SI, double p, double t)
{
return (SI * 100)/(p*t);
}
/// <summary>
/// Gets the interest time span.
/// </summary>
/// <param name="SI" />The Simple Interest.
/// <param name="p" />The Principal.
/// <param name="r" />The Rate.
/// <returns>Interest time span
static double getInterestTimeSpan(double SI, double p, double r)
{
return (SI * 100) / (p * r);
}
}
Generic Delegate
Generic Delegate was introduced in .NET 3.5 that don't require to define the delegate instance in order to invoke the methods.
There are three types of generic delegates:
- Func
- Action
- Predicate
Generic Delegate: Func
The
Func
delegate defines a method that can be called on arguments and returns a result. In the given code example, delegate Func<interest,double>
is defined with Interest type
as argument and double
as return type.
Hide Shrink Copy Code
/// <summary>
/// Sample example of generic delegate
///
class Program
{
// Declare a delegate
delegate double CalculateSimpleInterest(double para1, double para2, double para3);
static CalculateSimpleInterest dObjSI = getTotalInterest;
static void Main(string[] args)
{
double SI;
//Declare a generic Func delegate
Func<interest,double> calcSI = SIObj =>(SIObj.P*SIObj.T*SIObj.R)/100;
Interest obj = new Interest();
obj.P = 120; obj.T = 1; obj.R = 3.25;
// Consuming delegate
SI = calcSI(obj);
Console.WriteLine("Total Interest of $120 in a year at rate of 3.25% APR is {0}", SI);
Console.ReadKey();
}
}
class Interest
{
public double P { get; set; }
public double T { get; set; }
public double R { get; set; }
}
</interest,double>
Generic Delegate: Action
The
Action
delegate defines a method that can be called on arguments but does not return a result. In the given code example, delegate Action<string>
is defined with string
as argument.
Hide Copy Code
Action<string> MyAction = y => Console.Write(y);
MyAction("Hello");
Console.ReadKey();
Generic Delegate: Predicate
The Predicate delegate defines a method that can be called on arguments and always returns Boolean type result. In the given code example, delegate
Predicate<string> checkValidDate
is defined with string
type as argument and returns bool
type.
Hide Copy Code
/// <summary>
/// Sample example of generic delegate: Predicate
///
class Program
{
static void Main(string[] args)
{
string date="05/12/20143";
Predicate<string> checkValidDate = d => IsDate(d) ;
if (checkValidDate(date))
{
Console.WriteLine("Valid Date");
}
else
{
Console.WriteLine("Invalid Date");
}
Console.ReadKey();
}
private static bool IsDate(string date)
{
DateTime dt;
return DateTime.TryParse(date,out dt);
}
}
</string>
Expression Tree
Expression trees allow you to build code dynamically at runtime instead of statically typing it in the IDE and using a compiler. Expression Trees use generic delegates to create and parse the expressions.
Expression trees are used in the following cases:
- Expression trees can be used to create LINQ to SQL and EF to SQL.
- Expression trees can be used for ASP.NET MVC's HTML extensions.
- Expression trees can be used to determine the selected property or field in MVC.
In the given code example, a expression (3+5)-(4-2) is divided into three expressions as Exp1 for (3+5), Exp2 for (4-2) and Exp3 for adding Exp1 and Exp2. The expression
Expression.Lambda<func<int>>(resultexp).compile()()
uses Func
generic delegate to parse the expressions.
Hide Copy Code
/// <summary>
/// Sample example of Expression Tree
///
class Program
{
static void Main(string[] args)
{
//Express tree (3+5)-(4-2)
//3+5
BinaryExpression Exp1 = Expression.MakeBinary(ExpressionType.Add, Expression.Constant(3),
Expression.Constant(5));
//4-2
BinaryExpression Exp2 = Expression.MakeBinary(ExpressionType.Subtract, Expression.Constant(4),
Expression.Constant(2));
// (3+5)-(4-2)
BinaryExpression resultExp = Expression.MakeBinary(ExpressionType.Subtract, Exp1, Exp2);
//this stmt will create a delegates by parsing the expression three
int result = Expression.Lambda<func<int>>
(resultexp).compile()(); console.writeline("result="{0}",">
Difference Between Each Type of Generic Delegate
Func | Action | Predicate | |
Arguments | Yes | Yes | Yes |
Returns | Yes | No | Boolean Type Only |
--------------------------------------------------------------------------
In .net 3.5 some new generic delegates -Func<T>, Action<T> and Predicate<T> were introduced. Using generic delegates, it is possible to concise delegate type means you don’t have to define the delegate statement. These delegates are the Func<T>, Action<T> and Predicate<T> delegates and defined in the System namespace.
Action<T> performs an operation on the generic arguments. Func<T> performs an operationon the argument(s) and returns a value, and Predicate<T> is used to represent a set of criteria and determine if the argument matches the criteria.
- delegate TResult Func
(); delegate TResult Func (T arg); delegate TResult Func (T1 arg1, T2 arg2); ... up to T16 delegate void Action (); delegate void Action (T arg); delegate void Action (T1 arg1, T2 arg2); ... up to T16
Here "in" shows the input parameters and "out" shows the return value by the delegate.
Generic delegate example
- using System;
- class demo
- {
- delegate void MyDelegate(string str);
- static void Main(string[] args)
- {
- MyDelegate d = show;
- d("Hello World!");
- Console.ReadLine();
- }
- static void show(string str)
- {
- Console.WriteLine(str);
- }
- }
Above code can be written as using generic delegate.
- using System;
- class demo
- {
- static void Main(string[] args)
- {
- Action<string> d = show;
- d("Hello World!");
- Console.ReadLine();
- }
- static void show(string str)
- {
- Console.WriteLine(str);
- }
- }
Generic delegate using anonymous method
- using System;
- class demo
- {
- static void Main(string[] args)
- {
- Action<string> d = s => Console.WriteLine(s);
- d("Hello World!");
- }
- }
Func in C#:
We have learned in the previous section, that a delegates can be defined as shown below.Example: C# Delegatepublic delegate int SomeOperation(int i, int j); class Program { static int Sum(int x, int y) { return x + y; } static void Main(string[] args) { SomeOperation add = Sum; int result = add(10, 10); Console.WriteLine(result); } }
Output:20C# 3.0 includes built-in generic delegate types Func and Action, so that you don't need to define custom delegates as above.Func is a generic delegate included in the System namespace. It has zero or more inputparameters and one out parameter. The last parameter is considered as an out parameter.For example, a Func delegate that takes one input parameter and one out parameter is defined in the System namespace as below:Func in C#:namespace System { public delegate TResult Func<in T, out TResult>(T arg); }
The last parameter in the angle brackets <> is considered as the return type and remaining parameters are considered as input parameter types as shown in the following figure.A Func delegate with two input parameters and one out parameters will be represent as below.The following Func type delegate is the same as the above SomeOperation delegate, where it takes two input parameters of int type and returns a value of int type:C#:Func<int, int, int> sum;
You can assign any method to the above func delegate that takes two int parameters and returns an int value. Now, you can take Func delegate instead of someOperation delegate in the first example.Example: Funcclass Program { static int Sum(int x, int y) { return x + y; } static void Main(string[] args) { Func<int,int, int> add = Sum; int result = add(10, 10); Console.WriteLine(result); } }
Output:20A Func delegate type can include 0 to 16 input parameters of different types. However, it must include one out parameter for result. For example, the following func delegate doesn't have any input parameter, it includes only a out parameter.Example: Func with zero input parameterFunc<int> getRandomNumber;
Func with an Anonymous method:
You can assign an anonymous method to the Func delegate by using the delegate keyword.Example: Func with anonymous methodFunc<int> getRandomNumber = delegate() { Random rnd = new Random(); return rnd.Next(1, 100); };
Func with lambda expression:
A Func delegate can also be used with a lambda expression, as shown below:Example: Func with lambda expressionFunc<int> getRandomNumber = () => new Random().Next(1, 100); //Or Func<int, int, int> Sum = (x, y) => x + y;
Points to Remember :
- Func is built-in delegate type.
- Func delegate type must return a value.
- Func delegate type can have zero to 16 input parameters.
- Func delegate type can be used with an anonymous method or lambda expression.
Points to Remember :
- Predicate delegate takes one input parameter and boolean return type.
- Predicate delegate must contains some criateria to check whether supplied parameter meets those criateria or not.
- Anonymous method and Lambda expression can be assigned to the predicate delegate.
Points to Remember :
- Delegate is a function pointer. It is reference type data type.
- Syntax: public delegate void <function name>(<parameters>)
- A method that is going to assign to delegate must have same signature as delegate.
- Delegates can be invoke like a normal function or Invoke() method.
- Multiple methods can be assigned to the delegate using "+" operator. It is called multicast delegate.
No comments:
Post a Comment