Fundamentals of Delegates

Introduction

A function is an action whose role can be requested or called anytime, without going through a class as is the case for a method of a class. This concept is supported in the .NET Framework as a delegate and made available to C# (and the other .NET languages).

As you probably know from C#, a class can contain one or more methods used to perform operations. Here is an example:

public class Exercise
{
    public void Create()
    {
        WriteLine("Actions speak louder than words");
    }
}

Such a method must be explicitly called. Here is an example:

using static System.Console;

public class Sociology
{
    public void Create()
    {
        WriteLine("Actions speak louder than words...");
    }
}
public class Exercise
{
    public static int Main()
    {
        Sociology socio = new Sociology();
        
        socio.Create();

        WriteLine("=================================");
        return 0;
    }
}

This would produce:

Actions speak louder than words...
=================================
Press any key to continue . . .

The basic formula to create a delegate is:

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

You can start with some opions (such as attributes). 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 delegae 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 named of methods.

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:

public delegate string Observation();

public class Sociology
{
}

You can also create a delegate in a file that contains a controller class. Here is an example:

public delegate void Observation();

public class Exercise
{

}

As mentioned already, a delegate is primarily a syntax for a method and it is used to refer to an actual method. To use a delegate, you must define a method that would carry an assignment. That method must have the same return type and the same (number of) argument(s), if any. Here is an example:

public delegate void Observation();

public class Sociology
{
    public void Create()
    {
        string sentence = "A man with one watch knows what time it is; a man with two watches is never quite sure. - Lee Segall -";
    }
}

Here is an example of the method created in a class:

using static System.Console;

public delegate void Observation();

public class Conversation
{
    public void Create()
    {
        WriteLine("A man with one watch knows what time it is; a man with two watches is never quite sure. - Lee Segall -");
    }
}

Associating a Method to a Delegate

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

Accessing a Delegate

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

using static System.Console;

public delegate void Observation();

public class Sociology
{
    public void Hold()
    {
        WriteLine("A man with one watch knows what time it is; a man with two watches is never quite sure. - Lee Segall -");
    }
}
public class Exercise
{
    public static int Main()
    {
        Sociology socio = new Sociology();
        Observation quote = new Observation(socio.Hold);

        quote();

        WriteLine("======================================================================================================");
        return 0;
    }
}

This would produce:

A man with one watch knows what time it is; a man with two watches is never quite sure. - Lee Segall -
======================================================================================================
Press any key to continue . . .

Introductory Topics on Delegates

A Static Method for a Delegate

If the class that contains the method is static, you must define the method as static. Here is an example of such a method:

public delegate void Observation();

public static class Reflections
{
    public static void Create()
    {
    }
}

Even if that class is not static, you can still define the method as static. In both cases, you would not need to declare the variable first. Here is an example:

using static System.Console;

public delegate void Observation();

public static class Reflections
{
    public static void Say()
    {
        WriteLine("I feel like I've got a guest come to my house, unexpected, stayed three weeks uninvited, and then they start complaining about the food. - Robert Blasier - Attorney at Law -");
    }
}

public class Exercise
{
    public static int Main()
    {
        Observation validation = Reflections.Say;

        validation();


        WriteLine("===========================================================================================================");
        return 0;
    }
}

This would produce:

I feel like I've got a guest come to my house, unexpected, stayed three weeks uninvited, and then they start complaining about the food. - Robert Blasier - Attorney at Law -
===========================================================================================================
Press any key to continue . . .

An Anonymous Delegate

In the above examples, we had to create a method that would be associated with a delegate. As an alternative, you can first create a delegate. Here is an example:

public delegate void Observation();

Then, when you need to use it, create a type of local implementation of a method and use it. In other words, you don't have to define a formal method that would initialize the delegate. Such a method is referred to as anonymous.

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:

public class Exercise
{
    Observation example = delegate ()
    {
        return "If reality TV has taught us anything, it's that you can't keep people with no shame down. - 30 Rock (NBC) -";
    };
}

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

using static System.Console;

public delegate void Observation();

public class Exercise
{
    public static int Main()
    {
        Title = "Conversations";

        Observation remark = delegate ()
        {
            WriteLine("If reality TV has taught us anything, it's that you can't keep people with no shame down. - 30 Rock (NBC) -");
        };

        remark();

        WriteLine("===========================================================================================================");
        return 0;
    }
}

This would produce:

If reality TV has taught us anything, it's that you can't keep people with no shame down. - 30 Rock (NBC) -
===========================================================================================================
Press any key to continue . . .

The Lambda Operator

You can also create an anonymous method using an operator called lambda and represented as =>. 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 static System.Console;

public delegate void Observation();

public class Exercise
{
    public static int Main()
    {
        Title = "Conversations";

        Observation remark = () =>
        {
            WriteLine("If reality TV has taught us anything, it's that you can't keep people with no shame down. - 30 Rock (NBC) -");
        };

        remark();

        WriteLine("===========================================================================================================");
        return 0;
    }
}

Delegates Compositions

Adding Delegates

A delegate can be added to another delegate using the + operation. 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 method, 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 method 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. This can be done as follows:

result = first;
result += second;

Delegates and Parameters

A Delegate that Uses a Parameter

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

delegate void Observation(string arg);

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

public delegate void Observation(string msg);

public class Sociology
{
    public void Create(string say)
    {
    }
}

To associate the method to the delegate, declare a variable for the delegate and initialize it with the method. To use the variable, when calling it, pass an argument. Here is an example:

using static System.Console;

public delegate void Observation(string msg);

public class Sociology
{
    public void Create(string say)
    {
        WriteLine(say);
    }
}

public class Exercise
{
    public static int Main()
    {
        Sociology socio = new Sociology();
        Observation quote = socio.Create;

        quote("Les dances à la gloire de la fornication.");

        WriteLine("=========================================");
        return 0;
    }
}

This would produce:

Les dances à la gloire de la fornication.
=========================================
Press any key to continue . . .

In the same way, you can declare various variables of the same delegate. Whan calling each variable, pass the desired and appropriate argument.

In the same way, you can use any type of parameter.

A Delegate with Many Parameters

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

delegate void Operation(string n, double x, char c, double y);

A method that will be associated to the delegate must take the same types and order of parameters. Here is an example:

using static System.Console;

public delegate void Operation(string n, double x, char c, double y);

public class Arithmetic
{
    public void Add(string name, double first, char oper, double second)
    {
        double result = first + second;
    }
}

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

using static System.Console;

public delegate void Operation(string n, double x, char c, double y);

public class Arithmetic
{
    public void Add(string name, double first, char oper, double second)
    {
        double result = first + second;

        WriteLine(first + " + " + second + " = " + result);
    }

    public void Multiply(string identification, double number, char symbol, double factor)
    {
        double result = number * factor;

        WriteLine(number + " * " + factor + " = " + result.ToString());
    }
}

public class Exercise
{
    public static int Main()
    {
        Arithmetic numerical = new Arithmetic();

        Operation number = numerical.Add;
        Operation times = new Operation(numerical.Multiply);

        number("Addition", 2946.24, '+', 8253.44);
        times("Multiplication", 208.73, '*', 95.86);

        WriteLine("=========================================");
        return 0;
    }
}

This would produce:

2946.24 + 8253.44 = 11199.68
208.73 * 95.86 = 20008.8578
=========================================
Press any key to continue . . .

Parameterized Delegates and Lambda Expressions

You can create an anonymous method for a delegate that takes one or more parameters. Of course, you must first create a delegate. Here is an example:

public delegate void Description(string m, string n, int s);

Remember that, to create an anonymous delegate, you can use the delegate keyword. Here is an example:

using static System.Console;

public delegate void Description(string m, string n, int s);

public class Exercise
{
    public static int Main()
    {
        Description sayit = delegate (string strName, string units, int items)
        {
            WriteLine("A " + strName + " uses " + items + " " + units);
        };

        return 0;
    }
}

When calling the delegate variable, in its parentheses, pass each argument as the same type and order as a parameter of the delegate. Here are examples:

using static System.Console;

public delegate void Description(string m, string n, int s);

public class Exercise
{
    public static int Main()
    {
        Description sayit = delegate (string strName, string units, int items)
        {
            WriteLine("A " + strName + " uses " + items + " " + units);
        };

        Title = "Descriptions";

        sayit("square", "sides", 4);

        WriteLine("----------------------------------");
        
        sayit("water molecule", "atoms", 3);

        WriteLine("=========================================");
        return 0;
    }
}

This would produce:

A square uses 4 sides
----------------------------------
A water molecule uses 3 atoms
=========================================
Press any key to continue . . .

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. After defining the method, you can call it like a normal method. Here is an example:

using static System.Console;

public delegate void Description(string m, string n, int s);

public class Exercise
{
    public static int Main()
    {
        Description sayit = (string strName, string units, int items) =>
        {
            WriteLine("A " + strName + " uses " + items + " " + units);
        };

        Title = "Descriptions";

        sayit("square", "sides", 4);
        WriteLine("----------------------------------");
        sayit("water molecule", "atoms", 3);

        WriteLine("=========================================");
        return 0;
    }
}

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 static System.Console;

public delegate void Description(string m, string n, int s);

public class Exercise
{
    public static int Main()
    {
        Description sayit = (strName, units, items) =>
        {
            WriteLine("A " + strName + " uses " + items + " " + units);
        };

        Title = "Descriptions";

        sayit("square", "sides", 4);
        WriteLine("----------------------------------");
        sayit("water molecule", "atoms", 3);

        WriteLine("=========================================");
        return 0;
    }
}

A Delegate as a Type

Returning a Delegate from a Method

Because a delegate is a type, you can create a method that returns it. Here is an example:

using static System.Console;

public delegate void Observation();

public class Strong
{
    public Observation Produce()
    {
    }
}

In the body of the method, do what you want. At the end of the method, make sure you return a value or object that is the type of the delegate. For example, or at a minimum, you can declare a variable of the delegate and initialize it as we have done so far, then return that variable. Here is an example:

public delegate void Observation();

public class Sociology
{
    public void Hold()
    {
    }

    public Observation Produce()
    {
        Observation quote = new Observation(Hold);

        return quote;
    }
}

To use the method, you can declare a variable of the type of the delegate and you can initialize it with a call to the method that returns the delegate. You can then call the new variable as a method. Here ia an example:

using static System.Console;

public delegate void Observation();

public class Sociology
{
    public void Hold()
    {
        WriteLine("A man with one watch knows what time it is; a man with two watches is never quite sure. - Lee Segall -");
    }

    public Observation Produce()
    {
        Observation quote = new Observation(Hold);

        return quote;
    }
}

public class Exercise
{
    public static int Main()
    {
        Sociology socio = new Sociology();
        Observation quote = new Observation(socio.Produce());

        quote();

        WriteLine("=======================================================================================================");
        return 0;
    }
}

This would produce:

A man with one watch knows what time it is; a man with two watches is never quite sure. - Lee Segall -
=======================================================================================================
Press any key to continue . . .

In the above code, we use the default constructor of the class to access its method. As an alternative, you can assign the call directly to the variable. This can be done as follows:

public class Exercise
{
    public static int Main()
    {
        Sociology socio = new Sociology();
        
        Observation quote = socio.Produce();

        quote();

        return 0;
    }
}

Passing a Delegate (Method) as Parameter

Most languages don't allow passing a method (called function or procedure) as argument. 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 method you want to use. Here is an example of a simple delegate:

public delegate void Observation();

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

public delegate void Observation();

public class Exercise
{
    public void Hold()
    {   
    }
}

After doing this, you can create a method to which you would pass the delegate as parameter. Here is an example:

public delegate void Observation();

public class Exercise
{
    public void Hold()
    {
            
    }

    public void Create(Observation speech)
    {

    }
}

In the body of the method, call the delegate as a mehod. Here is an example:

public delegate void Observation();

public class Exercise
{
    public void Hold()
    {
    }

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

When calling the method that takes a delegate as parameter, pass the name of the method that is associated to the delegate. Here is an example:

using static System.Console;

public delegate void Observation();

public class Sociology
{
    public void Hold()
    {
        WriteLine("A man with one watch knows what time it is; a man with two watches is never quite sure. - Lee Segall -");
    }

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

public class Exercise
{
    public static int Main()
    {
        Sociology socio = new Sociology();
        Observation popular = new Observation(socio.Hold);

        socio.Create(popular);

        WriteLine("=======================================================================================================");
        return 0;
    }
}

Of course the methods don't have to belong to the same class. Consider the following example:

using static System.Console;

public delegate void Observation();

public class Sociology
{
    public void Hold()
    {
        WriteLine("A man with one watch knows what time it is; a man with two watches is never quite sure. - Lee Segall -");
    }   
}

public class Wisdom
{
    public void Create(Observation speech)
    {
        speech();
    }
}

public class Exercise
{
    public static int Main()
    {
        Sociology socio = new Sociology();
        Observation popular = new Observation(socio.Hold);

        Wisdom wise = new Wisdom();

        wise.Create(popular);

        WriteLine("=======================================================================================================");
        return 0;
    }
}

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 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 provide a large library of classes you can use.


Previous Copyright © 2008-2019, FunctionX Next