Home

Introduction to Delegates

Fundamentals of Delegates

Introduction

Throughout our lessons, we refer to a function a section of code that solves a problem but that function is created in the document that includes the Main() function.

A function is a section of code that takes care of a job. The role of a function can be used or revealed by calling the function. Consider an example of a function as follows

void Create()
{
    MessageBox.Show("Actions speak louder than words", "Citations");
}

To use such a function, you must explicitly call it. Here is an example:

using System;
using System.Windows.Forms;

namespace Exercise
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        void Create()
        {
            MessageBox.Show("Actions speak louder than words", "Citations");
        }

        private void btnProcess_Click(object sender, EventArgs e)
        {
            Create();
        }
    }
}

In the strict sense and in the tradition of the C++ language, a function is created indipendently of any class so that the function can be called anytime, without going through a class. This concept of funcions is supported in the .NET Framework with the name of delegate and made available to C# (and the other .NET languages).

Practical LearningPractical Learning: Introducing Delegates

  1. Start Microsoft Visual Studio. On the Visual Studio 2019 dialog box, click Create a New Project and click Next (if Microsoft Visual Studio was already opened, on the main menu, click File -> New -> Project...)
  2. In the list of projects templates, click Windows Forms App (.NET Framework)
  3. Click Next
  4. Change the project Name to PayrollPreparation06
  5. Click Create
  6. In the Solution Explorer, right-click Form1.cs -> Rename
  7. Type PayrollEvaluation to get PayrollEvaluation.cs
  8. Press Enter twice
  9. In the Toolbox, under Common Controls, click ComboBox
  10. Click the form
  11. While the combo box is selected on the form, in the Properties window, click Items and click its button
  12. In the text box of the String Collection Editor, type each of the following strings:
    None
    Utah
    Texas
    Alaska
    Nevada
    Florida
    Indiana
    Wyoming
    Illinois
    Michigan
    Colorado
    Tennessee
    Washington
    Pennsylvania
    South Dakota
    New Hampshire
    North Carolina
  13. Click OK
  14. Complete the design of the form as follows:

    Switch to the default Outcome

    Control (Name) Text TextAlign
    Label   Gross Salary:  
    TextBox txtGrossSalary 0 Right
    Label   State:
    ComboBox cbxStates    
    Button btnCalculate Calculate  
    Label   txtEmployeeResidence
    TextBox txtEmployeeResidence Right
    Label   txtIncomeTax
    TextBox Right
    Label   Net Pay:
    TextBox txtNetPay Right
  15. Double-click the Calculate button

Introduction to Creating a Delegate

So far in our lessons, we have studied two types that can be created from scratch. They are classes and enumerations. The delegate follows the same trend. This means that, like a class or an enumeration, a delegate can be created in its own file or in a file that also contains other types. To create a delegate in its own file, on the main menu, click Project -> Add New Item... Or, in the Solution Explorer, right-click the name of the project -> Add -> New Item... In the Add New Item dialog box, click Code File. Accept the default name of the file or change it. Click Add. In the document, type the necessary code. Remember that you can also create a delegate in a file that contains (a) class(es) and/or (an) enumeration(s).

The basic formula to create a delegate is:

[options] [modifier(s)] delegate void delegate-name ([formal-parameters]);

You can start with some opions. The modifiers can be one or an appropriate combination of the following keywords: new, public, private, protected, or internal. The delegate keyword is required. A delegate can be any of the types we have used so far. It can also be a type void. The delegate-name must be a valid C# name. The names of delegates follow the rules and suggestions of names of functions.

Because a delegate is some type of a template for a function or method, you must use parentheses, required for every function or method. If the function will not take any argument, leave the parentheses empty. Here is an example:

delegate string Observation();

A delegate is primarily a syntax for a function, but it is used to refer to an actual function. To use a delegate, you must define a function that would perform the actual job. That function must have the same return type and the same (number of) argument(s), if any. Here is an example:

delegate void Observation();

void Create()
{
    MessageBox.Show("A man with one watch knows what time it is; a man with two watches is never quite sure. - Lee Segall -",
                    "Citations");
}

ApplicationPractical Learning: Creating a Delegate

  1. Create a delegate as follows:
    using System;
    using System.Windows.Forms;
    
    delegate void Summarize();
    
    namespace PayrollPreparation08
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void btnCalculate_Click(object sender, EventArgs e)
            {
            }
        }
    }

Associating a Function to a Delegate

After creating the function, you can associate it to the name of the desired delegate. To do that, where you want to use the function, declare a variable of the type of the delegate. You have two options:

Practical LearningPractical Learning: Creating a Function for a Delegate

Accessing a Delegate

Once you have associated a function to a delegate variable, you can use the delegate variable as if it were a defined function. That is, you can call it as you would proceed for a normal function. Here is an example:

using System;
using System.Windows.Forms;

namespace Exercises
{
    delegate void Observation();

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        void Create()
        {
            MessageBox.Show("A man with one watch knows what time it is; " +
                            "a man with two watches is never quite sure. - Lee Segall -", 
                            "Citations");
        }

        private void btnProcess_Click(object sender, EventArgs e)
        {
            Observation quote = new Observation(Create);

            quote();
        }
    }
}

ApplicationPractical Learning: Accessing a Delegate

  1. Change the document as follows:
    using System;
    using System.Windows.Forms;
    
    delegate void Summarize();
    
    namespace PayrollPreparation080
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            void Estimate()
            {
                double taxes = 0.00;
                string residence = "";
    
                string state = cbxStates.Text;
                double salary = Convert.ToDouble(txtGrossSalary.Text);
    
                switch (state)
                {
                    case "Colorado":
                        taxes = salary * 4.63 / 100.00;
                        residence = "Colorado (4.63%)";
                        break;
                    case "Alaska":
                    case "Florida":
                        // Two of the 9 states that don't collect an income tax
                        taxes = 0.00;
                        residence = "No Income Tax";
                        break;
                    case "Illinois":
                        taxes = salary * 3.75 / 100.00;
                        residence = "Illinois (3.75%)";
                        break;
                    case "Indiana":
                        taxes = salary * 3.3 / 100.00;
                        residence = "Indiana (3.3%)";
                        break;
                    case "Nevada":
                    case "New Hampshire":
                    case "Tennessee":
                    case "Texas":
                        // Four other states that don't collect an income tax
                        taxes = 0.00;
                        residence = "Income Tax Not Collected";
                        break;
                    case "Michigan":
                        taxes = salary * 4.25 / 100.00;
                        residence = "Michigan (4.25%)";
                        break;
                    case "North Carolina":
                        taxes = salary * 5.75 / 100.00;
                        residence = "North Carolina (5.75%)";
                        break;
                    case "South Dakota":
                    case "Washington":
                    case "Wyoming":
                        // Three other states that don't collect an income tax
                        taxes = 0.00;
                        residence = "Income Tax Not Paid";
                        break;
                    case "Pennsylvania":
                        taxes = salary * 3.07 / 100.00;
                        residence = "Pennsylvania (3.07%)";
                        break;
                    case "Utah":
                        taxes = salary * 5 / 100.00;
                        residence = "Utah (5%)";
                        break;
                    default:
                        taxes = 0.00;
                        residence = "";
                        break;
                }
    
                txtEmployeeResidence.Text = residence;
                txtStateIncomeTax.Text = taxes.ToString("F");
                txtNetPay.Text = (salary - taxes).ToString("F");
            }
    
            private void btnCalculate_Click(object sender, EventArgs e)
            {
                Summarize sum = new Summarize(Estimate);
    
                sum();
            }
        }
    }
  2. To execute the project, on the main menu, click Debug -> Start Without Debugging
  3. In the Gross Salary text box, type a number such as 3266.48
  4. In the combo box, select a state, such as Pennsylvania
  5. Click the Calculate button:

    Introducing Switch Statements

  6. Close the form and return to your programming environment

Delegates and Parameters

Introduction

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

delegate void Simple(string arg);

When defining the associated method, make it take the same number and type(s) of parameters. Here is an example:

using System;
using System.Windows.Forms;

namespace Exercise
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        void Create(string msg)
        {
            MessageBox.Show(arg, "Citations");
        }
    }
}

To associate the function to the delegate, declare a variable for the delegate and initialize it. You can use the new operator and the name of the delegate

using System;
using System.Windows.Forms;

namespace Exercises
{
    delegate void Observation(string arg);

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        void Create(string msg)
        {
            MessageBox.Show(msg, "Citations");
        }

        private void BtnProcess_Click(object sender, EventArgs e)
        {
            Observation quote = new Observation(Create);
        }
    }
}

To simplify your code, you can simply assign the name of the function to the delegate variable. Here is an example:

private void BtnProcess_Click(object sender, EventArgs e)
{
    Observation quote = Create;
}

To actually use the delegate, when calling it, add the parentheses to it and in the parentheses, provide a value for the argument. Here is an example:

using System;
using System.Windows.Forms;

namespace Exercises
{
    delegate void Observation(string arg);

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        void Create(string msg)
        {
            MessageBox.Show(msg, "Citations");
        }

        private void BtnProcess_Click(object sender, EventArgs e)
        {
            string str = "Chemistry is the study of matter. Matter is the building " +
                         "block of anything in the environment, that is, anything " +
                         "that occupies any form of space, anything that can be " +
                         "seen or is hidden to the human eye.";

            Observation quote = new Observation(Create);

            quote(str);
        }
    }
}

In the above example, we used a string argument. In the same way, for the parameter, you can use any of the types we have used so far.

A Delegate with Many Parameters

A delegate can use more than one parameter. When creating the delegate, pass the same number and type(s) of parameter(s). Here is an example:

delegate void Operation(double x, string op, double y);

When calling the delegate from your variable, pass the appropriate number and type(s) of argument(s):

using System;
using System.Windows.Forms;

namespace Exercises
{
	delegate void Operation(double x, string op, double y);

	public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

		void Process(double number1, string oper, double number2)
		{
			double result = 0;

			switch (oper)
			{
				case "+":
					result = number1 + number2;
					break;

				case "-":
					result = number1 - number2;
					break;

				case "*":
					result = number1 * number2;
					break;

				case "/":
					if (number2 != 0)
						result = number1 / number2;
					break;
			}

			txtResult.Text = result.ToString();
		}
		
		private void btnCalculate_Click(object sender, EventArgs e)
        {
			double operand1 = double.Parse(txtNumber1.Text);
			double operand2 = double.Parse(txtNumber2.Text);

			Operation oper = new Operation(Process);

			oper(operand1, txtOperator.Text, operand2);
		}
    }
}

Primary Characteristics of Delegates

A Static Function for a Delegate

You can associate a delegate to a static function. In this case, to access the function, you must qualify it from its class. Here is an example:

using System;
using System.Windows.Forms;

namespace Exercise03
{
    delegate void Observation();

    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        static void Create()
        {
            MessageBox.Show("A man with one watch knows what time it is; " +
                            "a man with two watches is never quite sure. - Lee Segall -",
                            "Citations");
        }

        private void BtnProcess_Click(object sender, EventArgs e)
        {
            Observation obs = new Observation(Create);

            obs();
        }
    }
}

Delegates and Namespaces

As mentioned previously, you can create a delegate in its own file. If necessary, to reduce name conflict, you can create a delegate in a namespace. In this case, to access the delegate outside of its namespace, you must qualify the delegate. To do this, type the name of the namespace, a period, and the name of the delegate. Here is an example:

using System;
using System.Windows.Forms;

namespace Knowledge
{
    delegate void Observation();
}

namespace Exercises
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        void Create()
        {
            MessageBox.Show("A man with one watch knows what time it is; " +
                            "a man with two watches is never quite sure. - Lee Segall -",
                            "Citations");
        }

        private void btnProcess_Click(object sender, EventArgs e)
        {
            Knowledge.Observation obs = new Knowledge.Observation(Create);

            obs();
        }
    }
}

Lambda Expressions

Introduction

We have already seen that the C# language supports the idea of nesting a function inside another function or inside a method. Here is an example:

using System;
using System.Windows.Forms;

namespace Exercise
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnProcess_Click(object sender, EventArgs e)
        {
            Create();

            // Optional other code here

            void Create()
            {
                MessageBox.Show("A man with one watch knows what time it is; " +
                                "a man with two watches is never quite sure. - Lee Segall -",
                                "Citations");
            }
        }
    }
}

A nested function can be associated with a delegate, exactly as we have done so far. After creating such a function, you can call it in the nesting code, before or after the code of the function. Here is an example:

using System;
using System.Windows.Forms;

delegate void Observation();

namespace Exercises
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnProcess_Click(object sender, EventArgs e)
        {
            Observation obs = new Observation(Create);

            obs();

            void Create()
            {
                MessageBox.Show("A man with one watch knows what time it is; " +
                                "a man with two watches is never quite sure. - Lee Segall -",
                                "Citations");
            }
        }
    }
}

An Anonymous Delegate

In the previous examples, we had to create a function that would be associated with a delegate. In the same way, you can create a type of local implementation of a function (in an existing function). In other words, you don't have to define a formal function that would initialize the delegate. Such a function is referred to as anonymous.

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

using System;
using System.Windows.Forms;

namespace Exercises
{
    delegate void Observation();

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void BtnProcess_Click(object sender, EventArgs e)
        {
            Observation obs = delegate ()
            {
                MessageBox.Show("A man with one watch knows what time it is; " +
                                "a man with two watches is never quite sure. - Lee Segall -",
                                "Citations");
            };
        }
    }
}

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

using System;
using System.Windows.Forms;

namespace Exercises
{
    delegate void Observation();

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void BtnProcess_Click(object sender, EventArgs e)
        {
            Observation obs = delegate ()
            {
                MessageBox.Show("A man with one watch knows what time it is; " +
                                "a man with two watches is never quite sure. - Lee Segall -",
                                "Citations");
            };
            
            obs();
        }
    }
}

The Lambda Operator

You can also create an anonymous function 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;
using System.Windows.Forms;

delegate void Observation();

namespace Exercises
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnProcess_Click(object sender, EventArgs e)
        {
            Observation obs = () =>
            {
                MessageBox.Show("A man with one watch knows what time it is; " +
                                "a man with two watches is never quite sure. - Lee Segall -",
                                "Citations");
            };

            obs();
        }
    }
}

Parameterized Delegates and Lambda Expressions

You can create an anonymous method for a delegate that takes one or more parameters. 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, you can use or ignore the parameter. When calling the variable of the delegate, use the same rules we have applied so far. Here is an example:

using System;
using System.Windows.Forms;

delegate void Observation(string arg);

namespace Exercises
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnProcess_Click(object sender, EventArgs e)
        {
            Observation obs = delegate(string x)
            {
                MessageBox.Show(x, "Citations");
            };

            string msg = "A man with one watch knows what time it is; " +
                         "a man with two watches is never quite sure. - Lee Segall -";

            obs(msg);
        }
    }
}

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. In the body of the anonymous method, use the argument or ignore it as you see fit. Here is an example:

using System;
using System.Windows.Forms;

delegate void Observation(string arg);

namespace Exercises
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnProcess_Click(object sender, EventArgs e)
        {
            Observation obs = (string x) =>
            {
                MessageBox.Show(x, "Citations");
            };

            string msg = "A man with one watch knows what time it is; " +
                         "a man with two watches is never quite sure. - Lee Segall -";
            obs(msg);
        }
    }
}

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

using System;
using System.Windows.Forms;

delegate void Observation(string arg);

namespace Exercises
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnProcess_Click(object sender, EventArgs e)
        {
            Observation obs = (x) =>
            {
                MessageBox.Show(x, "Citations");
            };

            string msg = "A man with one watch knows what time it is; " +
                         "a man with two watches is never quite sure. - Lee Segall -";
            obs(msg);
        }
    }
}

In the same way, you can to use a lambda expression to create an anonymous function that uses many parameters. You can implement it with the delegate keyword. Here is an example:

using System;
using System.Windows.Forms;

namespace Exercises
{
    delegate void Operation(double x, string op, double y);

    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }
        
        private void btnCalculate_Click(object sender, EventArgs e)
        {
			double operand1 = double.Parse(txtNumber1.Text);
			double operand2 = double.Parse(txtNumber2.Text);

			Operation exam = delegate(double number1, string oper, double number2)
			{
				double result = 0;
				
				switch (oper)
				{
					case "+":
						result = number1 + number2;
						break;
						
					case "-":
						result = number1 - number2;
						break;
						
					case "*":
						result = number1 * number2;
						break;
						
					case "/":
						if (number2 != 0)
							result = number1 / number2;
						break;
				}
				
				txtResult.Text = result.ToString();
			};

			exam(operand1, txtOperator.Text, operand2);
	    }
    }
}

You can omit using the delegate keyword and use the => operator instead. Here is an example:

using System;
using System.Windows.Forms;

namespace Exercises
{
	delegate void Operation(double x, string op, double y);

	public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }
		
		private void btnCalculate_Click(object sender, EventArgs e)
        {
			double operand1 = double.Parse(txtNumber1.Text);
			double operand2 = double.Parse(txtNumber2.Text);

			Operation exam = (double number1, string oper, double number2) =>
			{
				double result = 0;
				
				switch (oper)
				{
					case "+":
						result = number1 + number2;
						break;
						
					case "-":
						result = number1 - number2;
						break;
						
					case "*":
						result = number1 * number2;
						break;
						
					case "/":
						if (number2 != 0)
							result = number1 / number2;
						break;
				}
				
				txtResult.Text = result.ToString();
			};

			exam(operand1, txtOperator.Text, operand2);
		}
    }
}

Once again, the data types of the parameters are optional.

A Delegate as a Parameter

Passing a Function as Argument

By default, in C#, you cannot pass a function as argument (although some other languages support that concept). Delegates provide an alternative. Because a delegate is an object, or rather treated as such, it can be used as a parameter.

To start, you must have or create a delegate that has the syntax of the function you want to use. Here is an example:

using System.Windows.Forms;

namespace Exercises
{
    delegate void Observation();

    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }
    }
}

Once you have the delegate, you can create a function with the same syntax but that performs the action you want. Here is an example:

using System.Windows.Forms;

namespace Exercises
{
    delegate void Observation();

    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        void Hold()
        {
           
        }
    }
}

After doing this, you can create a function to which you would pass the delegate as parameter. To do this, specify the name of the delegate as the data type of the parameter and add a name for the parameter. Here is an example:

using System.Windows.Forms;

namespace Exercises
{
    delegate void Observation();

    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        void Hold()
        {
        }

        void Create(Observation speech)
        {
        }
    }
}

In the body of the function, call the delegate as you would call a function. Here is an example:

using System.Windows.Forms;

namespace Exercises
{
    delegate void Observation();

    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        void Hold()
        {
        }

        void Create(Observation speech)
        {
            speech();
        }
    }
}

When you call the function that takes a delegate as parameter, pass the name of the function that is associated to the delegate. This can be done in a class as follows:

using System.Windows.Forms;

namespace Exercise02
{
    delegate void Observation();

    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        void Hold()
        {
            MessageBox.Show("A man with one watch knows what time it is; a man with two watches is never quite sure. - Lee Segall -",
                            "Citations");
        }

        void Create(Observation speech)
        {
            speech();
        }

        private void btnProcess_Click(object sender, System.EventArgs e)
        {
            Create(Hold);
        }
    }
}

In the body of the function that takes a delegate as parameter, we simply called the parameter as a function. In some cases, you will want or need to initialize the argument. To do that, use the new operation to assign the delegate to the parameter as done when declaring a variable of a class. In the parentheses of the delegate, pass the name of the function that actually performs the desired operation. Here is an example:

using System.Windows.Forms;

namespace Exercises
{
    delegate void Observation();

    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        void Hold()
        {            
        }
        
        void Create(Observation speech)
        {
            speech = new Observation(Hold);

            speech();
        }

        private void btnProcess_Click(object sender, System.EventArgs e)
        {
            Create(Hold);
        }
    }
}

Remember that if you have a function that is called either once or by only by another function, you can nest such a function in the body of the only function that needs its service. Here is an example:

using System.Windows.Forms;

namespace Exercises
{
    delegate void Observation();

    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        void Hold()
        {
            MessageBox.Show("A man with one watch knows what time it is; a man " +
                            "with two watches is never quite sure. - Lee Segall -",
                            "Citations");
        }

        private void btnProcess_Click(object sender, System.EventArgs e)
        {
            Create(Hold);
            
            void Create(Observation speech)
            {
                speech();
            }
        }
    }
}

A Function as Parameter in a Lambda Expression

Instead of formally defining the desired behavior in the body of the function that would be associated with a delegate passed as parameter, you can create that function simply as an empty placeholder. Then use a lambda expression to define the behavior you want for the function. In this case, in the body of the function that takes the delegate as parameter, initialize the parameter with the delegate keyword and parentheses. Then create a curly-delimited body in which you can perform the operation(s) you want. Here is an example:

using System.Windows.Forms;

namespace Exercise02
{
    delegate void Observation();

    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        void Hold()
        {
        }
        
        void Create(Observation speech)
        {
            speech = delegate ()
            {
                MessageBox.Show("A man with one watch knows what time it is; a man " +
                                "with two watches is never quite sure. - Lee Segall -",
                                "Citations");
            };

            speech();
        }

        private void btnProcess_Click(object sender, System.EventArgs e)
        {
            Create(Hold);
        }
    }
}

Speaking of the delegate keyword, remember that you can omit it and use the => operator instead. Here is an example:

using System.Windows.Forms;

namespace Exercise02
{
    delegate void Observation();

    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        void Hold()
        {
        }
        
        void Create(Observation speech)
        {
            speech = () =>
            {
                MessageBox.Show("A man with one watch knows what time it is; a man " +
                                "with two watches is never quite sure. - Lee Segall -",
                                "Citations");
            };

            speech();
        }

        private void btnProcess_Click(object sender, System.EventArgs e)
        {
            Create(Hold);
        }
    }
}

Speaking of the function used as an empty placeholder, you can simply create in the section that needs it. This can be done as follows:

using System.Windows.Forms;

namespace Exercise02
{
    delegate void Observation();

    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }
        
        void Create(Observation speech)
        {
            speech = delegate()
            {
                MessageBox.Show("A man with one watch knows what time it is; a man " +
                                "with two watches is never quite sure. - Lee Segall -",
                                "Citations");
            };

            speech();
        }

        private void btnProcess_Click(object sender, System.EventArgs e)
        {
            Create(Hold);

            void Hold() {}
        }
    }
}

Or like this:

using System.Windows.Forms;

namespace Exercise02
{
    delegate void Observation();

    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }
        
        void Create(Observation speech)
        {
            speech = () =>
            {
                MessageBox.Show("A man with one watch knows what time it is; a man " +
                                "with two watches is never quite sure. - Lee Segall -",
                                "Citations");
            };

            speech();
        }

        private void btnProcess_Click(object sender, System.EventArgs e)
        {
            Create(Hold);

            void Hold() {}
        }
    }
}

A Delegate with a Parameter

We have already seen that you can create a delegate that takes a parameter. Here is an example of a delegate that takes a string as parameter:

delegate void Observation(string x);

Such a delegate can be passed as parameter to a function. To start, create a function that uses the same syntax as the delegate and that performs the action you want. Here is an example:

using System.Windows.Forms;

namespace Exercises
{
    delegate void Observation(string x);

    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        void Hold(string msg)
        {
            MessageBox.Show(msg, "Citations");
        }
    }
}

Create a function that takes the delegate as patameter. In the body of the function, call the parameter as a function but pass an argument that is the same type the delegate takes. Then, when calling the function that takes the delegate as parameter, pass the name of the delegate-associated function as argument. Here is an example:

using System.Windows.Forms;

namespace Exercise02
{
    delegate void Observation(string x);

    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        void Hold(string msg)
        {
            MessageBox.Show(msg, "Citations");
        }
        
        void Create(Observation speech)
        {
            speech("A man with one watch knows what time it is; a man " +
                   "with two watches is never quite sure. - Lee Segall -");
        }

        private void btnProcess_Click(object sender, System.EventArgs e)
        {
            Create(Hold);
        }
    }
}

A Delegate with Parameters

You can create a delegate that takes more than one parameter. Follow the above steps to pass the delegate as argument.

A Method as Parameter in a Lambda Expression

Instead of creating a formal method that would be associated with a delegate passed as parameter, you can define a lambda expression in the place where the delegate variable is passed as argument.

Delegates Compositions

Adding Delegates

One of the characteristics that set delegates apart from C/C++ function pointers is that a delegate can be added to another using the + operator. This is referred to as composition. This is done by adding one delegate variable to another as in "result = a + b". After doing this, to access the action produced, call the variable as if it were a function, as in "result()". In the same way, you can add many delegates as in "result = a + b + c". or more. You can call the variable like a function as in "result()".

Delegates and Compound Addition

Besides the regular addition, delegates also support the compound addition performed using the += operator. It works exactly as in C# arithmetic. This means that you can first add a delegate to a variable and assign the result to the variable as follows:

result = first;
result = result + second;

As an alternative, you can use the += operator between the variable and the right operand.

Introduction to Delegates and Classes

Introduction to Delegates and Methods

Everything we learn about a function is also applicable to a method as long as we keep in mind that a method is a member of a class.

A delegate can be associated with a method of a class. If the delegate is created outside the class, the method must be accessible; that is, the method should be created as public or internal. This time, to access the method and associate it to a delegate, you have to first declare a variable of that class. Here is an example:

using System;
using System.Windows.Forms;

namespace Exercises
{
    delegate void Observation();

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnProcess_Click(object sender, EventArgs e)
        {
            Sociology soc = new Sociology();
            Observation obs = new Observation(soc.Create);

            obs();
        }
    }
}

public class Sociology
{
    public void Create()
    {
        MessageBox.Show("A man with one watch knows what time it is; " +
                        "a man with two watches is never quite sure. - Lee Segall -",
                        "Citations");
    }
}

Delegates and Classes

So far, we involved only primitive types with delegates, especially when it came to parameters. Indeed, any type of value can be passed to a delegate and subsequently to its associated method(s). You can use any appropriate class. For example you can create your own class, but as you know it already, the .NET Framework provides a rich library of classes you can use.

ApplicationPractical Learning: Ending the Lesson


Previous Copyright © 2008-2021, FunctionX Next