Home

Delegates and Events

 

Fundamentals of Delegates

 

Introduction

The C and C++ languages have long used the concept of function pointer. This was even more useful when programming for the Microsoft Windows operating systems because the Win32 library relies on the concept of callback functions. Callback functions are used in Microsoft Windows programming to process messages. For this reason and because of their functionality, callback functions were carried out in the .NET Framework but they were defined with the name of delegate.

A delegate is a special type of user-defined variable that is declared globally, like a class. A delegate provides a template for a method, like an interface provides a template for a class. Like an interface, a delegate is not defined. Its role is to show what a useful method would look like. To support this concept, a delegate can provide all the necessary information that would be used on a method. This includes a return type, no argument or one or more arguments.

 

Practical LearningPractical Learning: Introducing Delegates

  1. Start Microsoft Visual C# and create a Console Application named WattsALoan1
  2. To create a new class, on the main menu, click Project -> Add Class...
  3. Change the name of the file to LoanEvaluation and click Add
  4. Change the contents of the file as follows:
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace WattsALoan1
    {
        public class LoanEvaluation
        {
            public double GetPrincipal()
            {
                Console.Write("Enter the Principal:         $");
                double P = double.Parse(Console.ReadLine());
    
                return P;
            }
    
            public double GetInterestRate()
            {
                Console.Write("Enter the Interest Rate (%): ");
                double r = double.Parse(Console.ReadLine());
    
                return r;
            }
    
            public int GetPeriod()
            {
                Console.Write("Enter the number of months:  ");
                int t = int.Parse(Console.ReadLine());
    
                return t;
            }
        }
    }
  5. Access the Program.cs file and change it as follows:
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace WattsALoan1
    {
        public class Program
        {
            static int Main()
            {
                int NumberOfPeriods;
                double Principal, IntRate;
                LoanEvaluation loan = new LoanEvaluation();
    
            Console.WriteLine(
                "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
                Console.WriteLine("Loan Processing\n");
                Console.WriteLine(
                "This program allows you to calculate the amount of money a ");
                Console.WriteLine(
                "customer will owe at the end of the lifetime of a loan\n");
    
                Principal = loan.GetPrincipal();
                IntRate = loan.GetInterestRate();
                NumberOfPeriods = loan.GetPeriod();
            Console.WriteLine(
                "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
    
                Console.WriteLine("================================");
                Console.WriteLine("Loan Estimation");
                Console.WriteLine("--------------------------------");
                Console.WriteLine("Principal: {0:C}", Principal);
                Console.WriteLine("Interest:  {0:P}", IntRate / 100);
                Console.WriteLine("Period:    {0} months", NumberOfPeriods);
                Console.WriteLine("================================\n");
    
                return 0;
            }
        }
    }
  6. Execute the application test it.
    Here is an example:
     
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    Loan Processing
    
    This program allows you to calculate the amount of money a
    customer will owe at the end of the lifetime of a loan
    
    Enter the Principal:         $14500
    Enter the Interest Rate (%): 12.25
    Enter the number of months:  48
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    
    ================================
    Loan Estimation
    --------------------------------
    Principal: $14,500.00
    Interest:  12.25 %
    Period:    48 months
    ================================
    
    Press any key to continue . . .
  7. Close the DOS window
  8. In the above program, the clerk was asked to provide the number of months for the period of the loan. Depending on the loan, one customer may want to specify the number of days necessary to pay the loan. Another customer may want to pay a loan over a number of years. To make this possible, we will allow the clerk to select the type of period for a loan.
    Access the LoanProcecssing.cs file and change the file as follows:
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace WattsALoan1
    {
        class LoanEvaluation
        {
            public double GetPrincipal()
            {
                Console.Write("Enter the Principal:         $");
                double P = double.Parse(Console.ReadLine());
    
                return P;
            }
    
            public double GetInterestRate()
            {
                Console.Write("Enter the Interest Rate (%): ");
                double r = double.Parse(Console.ReadLine());
    
                return r;
            }
    
            public void GetPeriod(ref int TypeOfPeriod, ref int Periods)
            {
            Console.WriteLine("How do you want to enter the length of time?");
                Console.WriteLine("1 - In Days");
                Console.WriteLine("2 - In Months");
                Console.WriteLine("3 - In Years");
                Console.Write("Your Choice: ");
                TypeOfPeriod = int.Parse(Console.ReadLine());
    
                if (TypeOfPeriod == 1)
                {
                    Console.Write("Enter the number of days: ");
                    Periods = int.Parse(Console.ReadLine());
                }
                else if (TypeOfPeriod == 2)
                {
                    Console.Write("Enter the number of months: ");
                    Periods = int.Parse(Console.ReadLine());
                }
                else if (TypeOfPeriod == 3)
                {
                    Console.Write("Enter the number of years: ");
                    Periods = int.Parse(Console.ReadLine());
                }
                else
                {
                    TypeOfPeriod = 0;
                    // The user made an invalid selection. So, we will give up
                    Console.WriteLine("Bad Selection\n");
                }
            }
        }
    }
  9. Access the Program.cs file and change it as follows:
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace WattsALoan1
    {
        public class Program
        {
            static int Main()
            {
                int Periods = 0;
                int TypeOfPeriod = 0;
                double Principal, IntRate;
                string PeriodName = null;
                LoanEvaluation loan = new LoanEvaluation();
    
    	    Console.WriteLine(
    	"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
    	    Console.WriteLine(
    	"This program allows you to calculate the amount of money a ");
    	    Console.WriteLine(
    	"customer will owe at the end of the lifetime of a loan\n");
    
                Console.WriteLine("Loan Processing\n");
                Principal = loan.GetPrincipal();
                IntRate = loan.GetInterestRate();
    
                loan.GetPeriod(ref TypeOfPeriod, ref Periods);
                if (TypeOfPeriod == 0)
                {
                    // Since the user made a bad selection, stop the program here
                    return 0;
                }// Since this "if" condition has a "return 0" line, if the "if"
                // condition produces true, the "return 0" means the function
                // would be terminated. If the condition is false, the inside of
                // this "if" condition would not execute and the function would
                // continue. This means that, if the condition is false, then
                // the "else' is implied. Therefore, we don't have to write an
                // "else" condition: it is automatic.
    
                if (TypeOfPeriod == 1)
                {
                    PeriodName = "days";
                }
                else if (TypeOfPeriod == 2)
                {
                    PeriodName = "months";
                }
                else if (TypeOfPeriod == 3)
                {
                    PeriodName = "years";
                }
    
    	    Console.WriteLine(
    	"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
    
                Console.WriteLine("==================================");
                Console.WriteLine("Loan Estimation");
                Console.WriteLine("----------------------------------");
                Console.WriteLine("Principal: {0:C}", Principal);
                Console.WriteLine("Interest:  {0:P}", IntRate / 100);
                Console.WriteLine("Period:    {0} {1}", Periods, PeriodName);
                Console.WriteLine("==================================\n");
    
                return 0;
            }
        }
    }
  10. Execute the application and test it. Here is an example:
     
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    This program allows you to calculate the amount of money a
    customer will owe at the end of the lifetime of a loan
    
    Loan Processing
    
    Enter the Principal:         $7500.00
    Enter the Interest Rate (%): 8.75
    How do you want to enter the length of time?
    1 - In Days
    2 - In Months
    3 - In Years
    Your Choice: 3
    Enter the number of years: 4
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    ==================================
    Loan Estimation
    ----------------------------------
    Principal: $7,500.00
    Interest:  8.75 %
    Period:    4 years
    ==================================
    
    Press any key to continue . . .
  11. Close the DOS window

Creating a Delegate

To create a delegate, you use the delegate keyword. The basic formula used to create a delegate is:

[attributes] [modifiers] delegate ReturnType Name ([formal-parameters]);

The attributes factor can be a normal C# attribute.

The modifier can be one or an appropriate combination of the following keywords: new, public, private, protected, or internal.

The delegate keyword is required.

The ReturnType can be any of the data types we have used so far. It can also be a type void or the name of a class.

The Name must be a valid C# name.

Because a delegate is some type of a template for a method, you must use parentheses, required for every method. If this method will not take any argument, leave the parentheses empty.

Here is an example:

using System;

public delegate void Simple();

public class Program
{
    static int Main()
    {
        return 0;
    }
}

After declaring a delegate, it only provides a template for a method, not an actual method. In order to use it, you must define a method that would carry an assignment to perform. That method must have the same return type and the same (number of) argument(s), if any. For example, the above declared delegate is of type void and it does not take any argument. you can define a corresponding method as follows:

public delegate void Simple();

public class Exercise
{
    public void Welcome()
    {
        Console.WriteLine("Welcome to the Wonderful World of C# Programming!");
    }
}

With such a method implemented, you can associate it to the name of the delegate. To do that, where you want to use the method, declare a variable of the type of the delegate and assign the method to the delegate variable. Because you are assigning the method to a delegate, one of the rules of delegates is that you must not apply the parentheses to the method. Here is an example

public class Program
{
    static int Main()
    {
        Exercise exo = new Exercise();

        Simple msg = exo.Welcome;

        return 0;
    }
}

Accessing a Delegate

 

Introduction

Once you have assigned a method to a delegate variable, you can you the delegate variable as if it were a defined method. That is, you can call as you would a normal method. Here is an example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public delegate void Simple();

public class Exercise
{
    public void Welcome()
    {
        Console.WriteLine("Welcome to the Wonderful World of C# Programming!");
    }
}

namespace Delegates
{
    public class Program
    {
        static int Main()
        {
            Exercise exo = new Exercise();

            Simple msg = exo.Welcome;

            msg();

            return 0;
        }
    }
}

This would produce:

Welcome to the Wonderful World of C# Programming!
Press any key to continue . . .

A Static Method for a Delegate

In the above example, we had to declare a variable of the (Exercise) class before accessing the method. An alternative is to create the associated method as static. That way, you would not need to declare the variable first. Here is an example:

using System;

public delegate void Simple();

public class Exercise
{
    public static void Welcome()
    {
        Console.WriteLine("Welcome to the Wonderful World of C# Programming!");
    }
}

public class Program
{
    static int Main()
    {
        Simple msg = Exercise.Welcome;

        msg();

        return 0;
    }
}

An Anonymous Delegate

In the above examples, we had to create a method that would be associated with a delegate. You can create a delegate, then, when you need to use, create a type of local implementation of a method and use it. In other words, you do not have to explicitly define a method prior to using the delegate. Such a method is referred to as anymous.

Before implementing an anonymous method, first declare the delegate you will use:

using System;

public delegate void Simple();

public class Program
{
    static int Main()
    {
        return 0;
    }
}

To create an anonymous method, declare a variable for the delegate and assign it the delegate keyword as if it were a method. That is, followed by parentheses and curly brackets that would represent the body of the method. In the body of the anonymous method, do whatever you want. Here is an example:

using System;

public delegate void Simple();

public class Program
{
    static int Main()
    {
        Simple msg = delegate()
        {
            Console.WriteLine("Welcome to the Wonderful World of C# Programming!");
        };

        return 0;
    }
}

Once you have done this, you can then call the delegate variable as if it were a normal method. Here is an example:

using System;

public delegate void Simple();

public class Program
{
    static int Main()
    {
        Simple msg = delegate()
        {
            Console.WriteLine("Welcome to the Wonderful World of C# Programming!");
        };

        msg();

        return 0;
    }
}

The Lambda Operator

You can also create an anonymous method using an operator called lambda and represented by =>. From our example above, to use the lambda operator to create an anonymous method, omit the delegate keyword and follow the parentheses by the operator. Here is an example:

using System;

public delegate void Simple();

public class Program
{
    static int Main()
    {
        Simple msg = () =>
        {
            Console.WriteLine("Welcome to the Wonderful World of C# Programming!");
        };

        return 0;
    }
}

Once you have done this, you can call the delegate variable as a method. Here is an example:

using System;

public delegate void Simple();

public class Program
{
    static int Main()
    {
        Simple msg = () =>
        {
            Console.WriteLine("Welcome to the Wonderful World of C# Programming!");
        };

        msg();

        return 0;
    }
}

A Delegate that Returns a Value

You can create a delegate that returns a value. When creating the delegate, specify the data type to the left side of the name of the delegate. When defining a method that would be associated with the delegate, remember that the method must return the same type of value. In the body of the method, use it as you see fit. Before exiting the method, make sure you appropriately return a value.

To use the method, follow the same approach as above. This time, when calling the delegate variable, you should use the parentheses. Here is an example:

using System;

delegate double Doubler();

public class Exercise
{
    public static double MultiplyBy2()
    {
        return 255 * 2;
    }
}

public class Program
{
    static int Main()
    {
        Doubler By2 = Exercise.MultiplyBy2;

        Console.WriteLine("Number = {0}", By2());

        return 0;
    }
}

This would produce:

Number = 510
Press any key to continue . . .

In the same way, you can create an anonymous method that implements the delegate. To do this, follow the same rule we defined earlier. For example, you can use the delegate keyword. Here is an example:

using System;

delegate double Doubler();

public class Program
{
    static int Main()
    {
        Doubler By2 = delegate()
        {
            return 255 * 2;
        };

        Console.WriteLine("Number = {0}", By2());

        return 0;
    }
}

Or you can use the lambda operator:

using System;

delegate double Doubler();

public class Program
{
    static int Main()
    {
        Doubler By2 = () =>
        {
            return 255 * 2;
        };

        Console.WriteLine("Number = {0}", By2());

        return 0;
    }
}

Delegates Compositions

One of the characteristics that set delegates apart from C/C++ function pointers is that one delegate can be added to another using the + operation. This is referred to as composition. This is done by adding one delegate variable to another as in a = b + c.

 

Delegates and Arguments

 

Introduction

If you want to use a method that takes arguments and associate it to a delegate, when declaring the delegate, provide the necessary argument(s) in its parentheses. Here is an example of a delegate that takes two arguments (and returns a value):

delegate double Doubler(double x);

When defining the associated method, besides returning the same type of value if not void, make sure that the method takes the same number of arguments. Here is an example:

public class Algebra
{
    public static double MultiplyBy2(double a)
    {
        return a * 2;
    }
}

Using an Argumentative Delegate

To associate the method to the delegate, you can declare a variable for the delegate and assign the name of the method to it. Here is an example:

using System;

delegate double Doubler(double x);

public class Algebra
{
    public static double MultiplyBy2(double a)
    {
        return a * 2;
    }
}

public class Program
{
    static int Main()
    {
        Doubler dbl = Algebra.MultiplyBy2;

        Console.WriteLine("Result = {0}", dbl);

        return 0;
    }
}

Notice that only the name of the method is passed to the delegate. To actually use the delegate, when calling it, add the parentheses to it and in the parentheses, provide a value for the argument(s). Here is an example:

using System;

delegate double Doubler(double x);

public class Algebra
{
    public static double MultiplyBy2(double a)
    {
        return a * 2;
    }
}

public class Program
{
    static int Main()
    {
        Doubler dbl = Algebra.MultiplyBy2;

        Console.WriteLine("Result = {0}", dbl(248));

        return 0;
    }
}

This would produce:

Result = 496
Press any key to continue . . .

A Lambda Expression

You can create an anonymous method for a delegate that takes one or more arguments. You can do this using the delegate keyword. In its parentheses, pass an argument that is the same type as the argument of the delegate. Then, in the body of the method, do what you judge necessary. When calling the variable of the delegate, use the same rules we have applied so far. Here is an example:

using System;

delegate double Doubler(double x);

public class Program
{
    static int Main()
    {
        Doubler dbl = delegate(double alpha)
        {
            return alpha * 2;
        };

        Console.WriteLine("Result = {0}", dbl(248));

        return 0;
    }
}

This technique of using the delegate keyword was introduced in C# 2.0 and has been updated with the lambda operator. Therefore, this was probably the last time we use it since we have been able to apply to different types of delegates.

Instead of the delegate keyword, you can define an anonymous method using the lambda operator. In this case, in the parentheses of the lambda expression, enter the data type of the argument followed by its name. Here is an example:

using System;

delegate double Doubler(double x);

public class Program
{
    static int Main()
    {
        Doubler dbl = (double alpha) =>
        {
        };

        return 0;
    }
}

In the body of the anonymous method, use the argument as you see fit. Here is an example:

using System;

delegate double Doubler(double x);

public class Program
{
    static int Main()
    {
        Doubler dbl = (double alpha) =>
        {
            return alpha * 2;
        };

        return 0;
    }
}

After defining the method, you can call it like a normal method. Here is an example:

using System;

delegate double Doubler(double x);

public class Program
{
    static int Main()
    {
        Doubler dbl = (double alpha) =>
        {
            return alpha * 2;
        };

        Console.WriteLine("Result = {0}", dbl(248));

        return 0;
    }
}

In our example, we specified the type of the argument. If you want, you can let the compiler figure out the type of argument. In this case, pass only the name of the argument and not its type. Here is an example:

using System;

delegate double Doubler(double x);

public class Program
{
    static int Main()
    {
        Doubler dbl = (alpha) =>
        {
            return alpha * 2;
        };

        Console.WriteLine("Result = {0}", dbl(248));

        return 0;
    }
}

A Delegate With Many Arguments

A delegate can take more than one argument. To start, when declaring it, pass the desired number of arguments. If you will use a method to associate to the delegate, then create the method also. Here is an example:

delegate double Addition(double x, double y);

public class Algebra
{
    public static double Plus(double a, double b)
    {
        return a + b;
    }
}

To use the delegate, follow the techniques we have applied so far and call the delegate as a method. Here is an example:

using System;

delegate double Addition(double x, double y);

public class Algebra
{
    public static double Plus(double a, double b)
    {
        return a + b;
    }
}

public class Exercise
{
    static int Main()
    {
        Addition Operation = Algebra.Plus;

        Console.WriteLine("Result = {0}", Operation(52.04, 9.368));

        return 0;
    }
}

This would produce:

Result = 61.408
Press any key to continue . . .

If you want to use a lambda expression to create an anonymous method, in its parentheses, pass the right number of arguments. In the body of the anonymous method, use the arguments ad you see fit. To use the delegate, call it as you would a normal method. Here is an example:

using System;

delegate double Addition(double x, double y);

public class Exercise
{
    static int Main()
    {
        Addition Operation = (x, y) =>
        {
            return x + y;
        };

        Console.WriteLine("Result = {0}", Operation(52.04, 9.368));

        return 0;
    }
}
 

Practical LearningPractical Learning: Passing Arguments to a Delegate

  1. Access the LoanEvaluation.cs file and change it as follows:
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace WattsALoan1
    {
        public class LoanEvaluation
        {
            public double GetPrincipal()
            {
                Console.Write("Enter the Principal:         $");
                double P = double.Parse(Console.ReadLine());
    
                return P;
            }
    
            public double GetInterestRate()
            {
                Console.Write("Enter the Interest Rate (%): ");
                double r = double.Parse(Console.ReadLine());
    
                return r;
            }
    
            public double GetPeriod(ref int TypeOfPeriod, ref double Periods)
            {
            Console.WriteLine("How do you want to enter the length of time?");
                Console.WriteLine("1 - In Days");
                Console.WriteLine("2 - In Months");
                Console.WriteLine("3 - In Years");
                Console.Write("Your Choice: ");
                TypeOfPeriod = int.Parse(Console.ReadLine());
    
                if (TypeOfPeriod == 1)
                {
                    Console.Write("Enter the number of days: ");
                    Periods = double.Parse(Console.ReadLine());
                    return Periods / 360;
                }
                else if (TypeOfPeriod == 2)
                {
                    Console.Write("Enter the number of months: ");
                    Periods = double.Parse(Console.ReadLine());
                    return Periods / 12;
                }
                else if (TypeOfPeriod == 3)
                {
                    Console.Write("Enter the number of years: ");
                    Periods = double.Parse(Console.ReadLine());
                    return Periods;
                }
                else
                {
                    TypeOfPeriod = 0;
                    // The user made an invalid selection. So, we will give up
                    Console.WriteLine("Bad Selection\n");
                    return 0.00;
                }
            }
    
            // Interest = Principal * rate * time in years
            public double InterestAmount(double P, double r, double t)
            {
                return P * (r / 100) * t;
            }
        }
    }
  2. Access the Program.cs file
  3. To declare and use a delegate, change the Program.cs file as follows:
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace WattsALoan1
    {
        delegate double Add2Values(double Value1, double Value2);
    
        public class Program
        {
            static int Main()
            {
                double Principal, IntRate, Period, AmountPaidAsInterest;
                int TypeOfPeriod = 0;
                double Periods = 0D;
                string PeriodName = null;
                LoanEvaluation loan = new LoanEvaluation();
    
                Console.WriteLine("\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
    	    Console.WriteLine(
    	"This program allows you to calculate the amount of money a ");
    	    Console.WriteLine(
    	"customer will owe at the end of the lifetime of a loan\n");
    
                Console.WriteLine("Loan Processing\n");
                Principal = loan.GetPrincipal();
                IntRate   = loan.GetInterestRate();
                Period    = loan.GetPeriod(ref TypeOfPeriod, ref Periods);
                AmountPaidAsInterest =
                    loan.InterestAmount(Principal, IntRate, Period);
    
                // A lambda expression
                Add2Values Add = (double Value1, double Value2) =>
                {
                    return Value1 + Value2;
                };
    
                if (TypeOfPeriod == 0)
                {
                    // Since the user made a bad selection, stop the program here
                    return 0;
                }// Since this "if" condition has a "return 0" line, if the "if"
                // condition produces true, the "return 0" means the function
                // would be terminated. If the condition is false, the inside of
                // this "if" condition would not execute and the function would
                // continue. This means that, if the condition is false, then
                // the "else' is implied. Therefore, we don't have to write an
                // "else" condition: it is automatic.
    
                if (TypeOfPeriod == 1)
                {
                    PeriodName = "days";
                }
                else if (TypeOfPeriod == 2)
                {
                    PeriodName = "months";
                }
                else if (TypeOfPeriod == 3)
                {
                    PeriodName = "years";
                }
    
                Console.WriteLine("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
    
                Console.WriteLine("==================================");
                Console.WriteLine("Estimate on loan");
                Console.WriteLine("----------------------------------");
                Console.WriteLine("Principal: {0:C}", Principal);
                Console.WriteLine("Interest:  {0:P}", IntRate / 100);
                Console.WriteLine("Period:    {0} {1}", Periods, PeriodName);
                Console.WriteLine("--------------------------------");
                Console.WriteLine("Total Amount Paid:     {0:C}", Add);
                Console.WriteLine("Interest paid on Loan: {0:C}", 
    				AmountPaidAsInterest);
                Console.WriteLine("==================================\n");
    
                return 0;
            }
        }
    }
  4. Execute the program and test it. Here is an example:
     
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    This program allows you to calculate the amount of money a
    customer will owe at the end of the lifetime of a loan
    
    Loan Processing
    
    Enter the Principal:         $12500
    Enter the Interest Rate (%): 10.55
    How do you want to enter the length of time?
    1 - In Days
    2 - In Months
    3 - In Years
    Your Choice: 2
    Enter the number of months: 42
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    
    ==================================
    Estimate on loan
    ----------------------------------
    Principal: $12,500.00
    Interest:  10.55 %
    Period:    42 months
    --------------------------------
    Total Amount Paid:     $17,115.63
    Interest paid on Loan: $4,615.63
    ==================================
    
    Press any key to continue . . .
  5. Close the DOS window and return to your programming environment

A Delegate Passed as Argument

Using delegates, one method can be indirectly passed as argument to another method. To proceed, first declare the necessary delegate. Here is a example of such a delegate:

public delegate double Squared(double x);

public class Circle
{
    private double _radius;

    public double Radius
    {
        get { return _radius; }
        set { _radius = value; }
    }
}

A delegate can be passed as argument to a method. Such an argument would be used as if it were a method itself. This means that, when accessed in the body of the method, the name of the delegate must be accompanied by parentheses and if the delegate takes an argument or arguments, the argument(s) must be provided in the parentheses of the called delegate. Here is an example:

public delegate double Squared(double x);

public class Circle
{
    private double _radius;

    public double Radius
    {
        get { return _radius; }
        set { _radius = value; }
    }

    public double Area(Squared sqd)
    {
        return sqd(_radius) * Math.PI;
    }
}

After declaring a delegate, remember to define a method that implements the needed behavior of that delegate. You can define the associated method in a class other than the one where the delegate would be used. Here is an example:

using System;

public class Exercise
{
    public static double ValueTimesValue(double Value)
    {
        return Value * Value;
    }

    static int Main()
    {
        return 0;
    }
}

You can also define the method in the class where the delegate would be needed. Once the method that implements the delegate is known, you can use the delegate as you see fit. To do that, you can declare a variable of the type of that delegate and assign it to the variable. Here is an example:

using System;

public delegate double Squared(double x);

public class Circle
{
    private double _radius;

    public double Radius
    {
        get { return _radius; }
        set { _radius = value; }
    }

    public double Area(Squared sqd)
    {
        return sqd(_radius) * Math.PI;
    }
}

public class Exercise
{
    public static double ValueTimesValue(double Value)
    {
        return Value * Value;
    }

    static int Main()
    {
        Squared Sq = ValueTimesValue;

        return 0;
    }
}

This declaration gives life to the delegate and can then be used as we have proceed with delegates so far. Here is an example:

using System;

public delegate double Squared(double x);

public class Circle
{
    private double _radius;

    public double Radius
    {
        get {  return _radius; }
        set { _radius = value; }
    }

    public double Area(Squared sqd)
    {
        return sqd(_radius) * Math.PI;
    }
}

public class Exercise
{
    public static double ValueTimesValue(double Value)
    {
        return Value * Value;
    }

    static int Main()
    {
        Squared Sqr = ValueTimesValue;

        Console.WriteLine("Circle Area: {0}\n", Sqr(24.68));

        return 0;
    }
}

This would produce:

Circle Area: 609.1024

Press any key to continue . . .

In the same way, you can use a lambda expression to implement an anonymous method that would be associated with a delegate. Here is an example:

using System;

public delegate double Squared(double x);

public class Circle
{
    private double _radius;

    public double Radius
    {
        get { return _radius; }
        set { _radius = value; }
    }

    public double Area(Squared sqd)
    {
        return sqd(_radius) * Math.PI;
    }
}

public class Exercise
{
    static int Main()
    {
        Squared Sqr = (a) =>
        {
            return a * a;
        };

        Console.WriteLine("Circle Area: {0}\n", Sqr(24.68));

        return 0;
    }
}

Delegates and Classes

 

Introduction

So far, we have learned how to create and use delegate of primitive types. We learned how to create a void delegate, how to create a delegate that returns a value, and how to create a delegate that takes one or more argument. Just as a reminder, here is an example:

using System;

delegate double Multiplication();

public class Cube
{
    private double _side;

    public double Side
    {
        get { return _side; }

        set { _side = value; }
    }

    public Cube()
    {
        _side = 0;
    }

    public Cube(double s)
    {
        _side = s;
    }

    internal double Area()
    {
        return 6 * Side * Side;
    }

    internal double Volume()
    {
        return Side * Side * Side;
    }
}

public class Exercise
{
    static int Main()
    {
        Cube SmallBox = new Cube(25.58);

        Multiplication AreaDefinition = SmallBox.Area;
        Multiplication VolDefinition = SmallBox.Volume;

        Console.WriteLine("Cube  Characteristics");
        Console.WriteLine("Side:   {0}", SmallBox.Side);
        Console.WriteLine("Area:   {0}", AreaDefinition);
        Console.WriteLine("Volume: {0}\n", VolDefinition);

        return 0;
    }
}

This would produce:

Cube  Characteristics
Side:   25.58
Area:   3926.0184
Volume: 16737.925112

A Delegate that Returns an Object

A delegate can be created to return a value that is of a class type. Of course you must know the class you want to use because the compiler would like to know the type of value that the delegate would return. You can use one of the many built-in classes of the .NET Framework or you can create your own class. When creating the delegate, specify the name of the class to its left as the returned type of value. Here is an example:

delegate Person Creator();

public class Person
{
    public string FirstName;
    public string LastName;
}

After doing this, you can create a method that implements the delegate. The method must return the same type of value as the delegate. Here is an example:

using System;

delegate Person Creator();

public class Person
{
    public string FirstName;
    public string LastName;
}

public class Exercise
{
    private static Person Create()
    {
        Person pers = new Person();
        pers.FirstName = "Julius";
        pers.LastName = "Krands";
        return pers;
    }
}

To use the delegate, declare a variable for it and assign the method to it. Here is an example:

using System;

delegate Person Creator();

public class Person
{
    public string FirstName;
    public string LastName;
}

public class Exercise
{
    private static Person Create()
    {
        Person pers = new Person();
        pers.FirstName = "Julius";
        pers.LastName = "Krands";
        return pers;
    }

    static int Main()
    {
        Creator crt = Create;

        return 0;
    }
}

You can then call use the variable as you see fit. Instead of explicitly creating a method that implements the delegate, you can create an anonymous method using a lambda expression. In the body of the anonymous method, make sure you return a value of the type of the delegate. Here is an example:

using System;

delegate Person Creator();

public class Person
{
    public string FirstName;
    public string LastName;
}

public class Exercise
{
    static int Main()
    {
        Creator Create = () =>
        {
            var PersonalInformation = new Person();

            PersonalInformation.FirstName = "Julius";
            PersonalInformation.LastName = "Krands";

            return PersonalInformation;
        };
       
        Create();
        return 0;
    }
}

A Delegate that Takes an Object as Argument

A delegate can be created to receive a class type as argument. When creating the delegate, in its parentheses, specify the class whose value it takes as argument. Here is an example:

using System;

delegate void Anchor(Person p);

public class Person
{
    public string FirstName;
    public string LastName;
}

To use the delegate, you can first create a method that implements the delegate, then declare a variable for the delegate and assign the method to it. If you prefer to create an anonymous method using a lambda expression, in the parentheses, enter a name for the argument and use that argument in the body of the method as you see fit. Here is an example: 

public class Exercise
{
    static int Main()
    {
        Anchor personal = (individual) =>
        {
            Console.WriteLine("=//= Personal Information =//=");
            Console.WriteLine("First Name: {0}", sample.FirstName);
            Console.WriteLine("Last Name:  {0}", sample.LastName);
        };

        return 0;
    }
}

You can then call the method as you see fit. Here is an example:

using System;

delegate Person Creator();
delegate void Anchor(Person p);

public class Person
{
    public string FirstName;
    public string LastName;
}

public class Exercise
{
    static int Main()
    {
        var PersonalInformation = new Person();
        
        Creator Create = () =>
        {
            PersonalInformation.FirstName = "Julius";
            PersonalInformation.LastName = "Krands";

            return PersonalInformation;
        };
 
        Anchor personal = (individual) =>
        {
            Console.WriteLine("=//= Personal Information =//=");
            Console.WriteLine("First Name: {0}", individual.FirstName);
            Console.WriteLine("Last Name:  {0}", individual.LastName);
        };

        Create();
        personal(PersonalInformation);

        return 0;
    }
}

This would produce:

=//= Personal Information =//=
First Name: Julius
Last Name:  Krands
Press any key to continue . . .

In the same way:

  • You can create a delegate that takes a class as argument and returns a class type
  • You can create a delegate that takes more than one argument. One of the arguments could be a class type and the other(s) a class or a primitive type 

Events

 

Introduction

Except for the main class of your program (the class that contains the Main() method), every class is mostly meant to interact with other, either to request values and methods of the other classes or to provide other classes with some values or a behavior they need. When a class A requests a value or service from another class B, class A is referred to as a client of class B. This relationship is important not simply because it establishes a relationship between both classes but also because class B should be ready to provide the value or behavior that a client needs at a certain time.

While a class B is asked to provide some values or methods to another class A, many things would happen. In fact, there is an order that things should follow. For example, during the lifetime of a program, that is, while a program is running, a class may be holding a value it can provide to its client but at another time, that value may not be available anymore, for any reason; nothing strange, this is just the ways it happens. Because different things can happen to a class B while a program is running, and because only class B would be aware of these, it must be able to signal to the other classes when there is a change. This is the basis of events: An event is an action that occurs on an object and affects it in a way that its clients must be made aware of. Events are mostly familiar to those who do graphical (GUI) programming as they are able to "visually" work on Windows controls and as they are able to access the objects on which actions are happening and the objects that must know when these actions occur. Still, because events are dealt with in C#, you should be aware of their functionality.

Although events are mostly used in Windows controls programming, they can also be implemented in console applications.

Event Creation

An event is declared like a pseudo-variable but based on a delegate. Therefore, to declare an event, you must have a delegate that would implement it. Here is an example:

using System;

delegate void dlgSimple();

class Exercise
{
	public static void Welcome()
	{
	Console.WriteLine("Welcome to the Wonderful World of C# Programming!");
	}
}

To actually declare an event, you use the event keyword with the following formula:

[attributes] [modifiers] event type declarator;
[attributes] [modifiers] event type member-name {accessor-declarations};

The attributes factor can be a normal C# attribute.

The modifier can be one or a combination of the following keywords: public, private, protected, internal, abstract, new, override, static, virtual, or extern.

The event keyword is required. It is followed by the name of the delegate that specifies its behavior. If the event is declared in the main class, it should be made static. Like everything in a program, an event must have a name. This would allow the clients to know what (particular) event occurred. Here is an example:

using System;

delegate void dlgSimple();

class Exercise
{
	public static event dlgSimple Simply;

	public static void Welcome()
	{
	Console.WriteLine("Welcome to the Wonderful World of C# Programming!");
	}
}

After declaring the event, you must define a method that calls the event. Here is an example:

using System;

delegate void dlgSimple();

class Exercise
{
	public static event dlgSimple Simply;

	public static void Welcome()
	{
	Console.WriteLine("Welcome to the Wonderful World of C# Programming!");
	}

	public static void SayHello()
	{
		Simply();
	}
}

When the event occurs, its delegate would be invoked. This specification is also referred to as hooking up an event. As the event occurs (or fires), the method that implements the delegate runs. This provides complete functionality for the event and makes the event ready to be used. Before using an event, you must combine it to the method that implements it. This can be done by passing the name of the method to the appropriate delegate, as we learned when studying delegates. You can then assign this variable to the event's name using the += operator. Once this is done, you can call the event. Here is an example:

using System;

delegate void dlgSimple();

class Exercise
{
	public static event dlgSimple Simply;

	public static void Welcome()
	{
	Console.WriteLine("Welcome to the Wonderful World of C# Programming!");
	}

	public static void SayHello()
	{
		Simply();
	}

	static int Main()
	{
		Simply += new dlgSimple(Welcome);

		SayHello();

		return 0;
	}
}

Instead of the += operator used when initializing the event, you can implement add and remove of the event class. Here is an example:

using System;

delegate void dlgSimple();

class Exercise
{
    public event dlgSimple Simply
    {
	add
	{
		Simply += new dlgSimple(Welcome);
	}
	remove
	{
		Simply -= new dlgSimple(Welcome);
	}
    }

    public void Welcome()
    {
	Console.WriteLine("Welcome to the Wonderful World of C# Programming!");
    }
}

 

 

Previous Copyright © 2008-2016, FunctionX, Inc. Next