Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Delegates and Types of Delegates in C#

0.00/5 (No votes)
13 May 2014 10  
Concepts of Delegates and Types of Delegate in C#

Table Of Contents

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 string type 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

Func ActionPredicate
Arguments Yes Yes Yes
Returns Yes No Boolean Type Only

History

  • 13th May, 2014: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here