Saturday, February 27, 2016

C Sharp : Generic delegates Func, Action and Predicate with anonymous method

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().
    /// 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().
/// <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.
    /// <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.
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 stringtype as argument and returns bool type.
    /// <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.
/// <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

FuncActionPredicate
ArgumentsYesYesYes
ReturnsYesNoBoolean 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.
  1. delegate TResult Func ();
  2. delegate TResult Func (T arg);
  3. delegate TResult Func (T1 arg1, T2 arg2);
  4. ... up to T16
  5. delegate void Action ();
  6. delegate void Action (T arg);
  7. delegate void Action (T1 arg1, T2 arg2);
  8. ... up to T16
Here "in" shows the input parameters and "out" shows the return value by the delegate.

Generic delegate example

  1. using System;
  2. class demo
  3. {
  4. delegate void MyDelegate(string str);
  5. static void Main(string[] args)
  6. {
  7. MyDelegate d = show;
  8. d("Hello World!");
  9. Console.ReadLine();
  10. }
  11. static void show(string str)
  12. {
  13. Console.WriteLine(str);
  14. }
  15. }
Above code can be written as using generic delegate.
  1. using System;
  2. class demo
  3. {
  4. static void Main(string[] args)
  5. {
  6. Action<string> d = show;
  7. d("Hello World!");
  8. Console.ReadLine();
  9. }
  10. static void show(string str)
  11. {
  12. Console.WriteLine(str);
  13. }
  14. }

Generic delegate using anonymous method

  1. using System;
  2. class demo
  3. {
  4. static void Main(string[] args)
  5. {
  6. Action<string> d = s => Console.WriteLine(s);
  7. d("Hello World!");
  8. }
  9. }


Func in C#:

We have learned in the previous section, that a delegates can be defined as shown below.
Example: C# Delegate

public 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:
20
C# 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.
Func delegate
A Func delegate with two input parameters and one out parameters will be represent as below.
Func delegate
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: Func

class 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:
20
A 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 parameter

Func<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 method

Func<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 expression

Func<int> getRandomNumber = () => new Random().Next(1, 100);

//Or 

Func<int, int, int>  Sum  = (x, y) => x + y;

Points to Remember :

  1. Func is built-in delegate type.
  2. Func delegate type must return a value.
  3. Func delegate type can have zero to 16 input parameters.
  4. Func delegate type can be used with an anonymous method or lambda expression.

Points to Remember :

  1. Predicate delegate takes one input parameter and boolean return type.
  2. Predicate delegate must contains some criateria to check whether supplied parameter meets those criateria or not.
  3. Anonymous method and Lambda expression can be assigned to the predicate delegate.

Points to Remember :

  1. Delegate is a function pointer. It is reference type data type.
  2. Syntax: public delegate void <function name>(<parameters>)
  3. A method that is going to assign to delegate must have same signature as delegate.
  4. Delegates can be invoke like a normal function or Invoke() method.
  5. Multiple methods can be assigned to the delegate using "+" operator. It is called multicast delegate.

No comments:

Post a Comment