Abstract

In this article, you will learn how to create and manipulates Delegate types as well as C# events, which streamline the process of working with delegates types. Delegates provide a mechanism for defining and executing callbacks. Their flexibility allows you to define the exact signature of the callback, and that information becomes part of the delegate type itself. Delegates are type-safe, object-oriented and secure which reduce the common problems associated with using function pointers.

Delegates Overview

A Delegate is an abstraction of one or more function pointers. The .NET has implemented the concept of function pointer in form delegate .With delegates, you can treat a function as data. Delegates allow functions to be passed as parameters, returned from a function as a value, and stored in an array. The delegate has following characteristics.

  • Delegates are derived from System.MulticastDelegate class.
  • They have a signature and a return type. A function that is added to delegates must be compatible with this signature.
  • Delegates can point either static or instance methods.
  • Once a delegate object has been created, it may dynamically invoke the methods it points to at runtime.
  • Delegates can call methods synchronously and asynchronously.

The delegate contains a couple of useful fields. The first one holds a reference to an object, and the second holds a method pointer. When you invoke the delegate, the instance method is called on the contained reference. However, if the object reference is null, the runtime understands this to mean that the method is a static method. Moreover, invoking a delegate syntactically is the exact same as calling a regular function.

Once a delegate object has been formed and specified the mandatory information, it may dynamically invoke the methods it points at runtime. Every delegate Delegates are perfect for implementing callbacks. In the .NET framework, callback is still possible, and this functionality is accomplished in a much safer and more object-oriented manner using delegates. In essence, a delegate is type-safe object that points to another method in the application, which can be invoked at a later time.

Why Need Delegates

Historically, the Windows API made frequent use of C style function pointers to create Callbacks functions. Using callbacks, programmers were able to configure one function to report back to another function in the application. So, the objective behind using a callback is to handle button clicking, menu-selection, and mouse-moving activities. But the problem with this traditional approach is that the callback functions were not type-safe. In the .NET framework, callbacks are still possible using delegates with more efficient approach. Delegates maintain three important piece of information as follows:

  • The Parameters of method.
  • The Address of the method that it calls.
  • The return type of the method.

A delegate exists for situations in which you want to pass methods around to other methods. You are used to passing data to methods as parameters, but the idea of passing methods as an argument instead of data, might sound a little strange. However, there are cases in which you have a method that does something for instance invoking some other method. You do not know at compile time what this second methods is. That information is available only at runtime hence; Delegates are device to surpass such complications.

Defining a Delegates

The Delegates can be defined by delegate keyword. Its definition must be similar to the function signature. A delegate can be defined in a namespace and within a class. A delegate cannot be used as a data member of a class or local variable within a method. The prototype for defining a delegate type as follows:

accessibility delegate return type delegatename(parameterlist);

Delegate declarations look almost exactly like abstract method declarations, except they have one added keyword: the delegate keyword. The following is a valid delegate declaration

public delegate int operation(int x, int y);

When the C# compiler encounters this line, it defines a type derived from MulticastDelegate, which also implements a method named Invoke that has exactly the same signature as the method described in the delegate declaration. For all practical purposes, that class looks like the following:

public class operation : System.MulticastDelegate
    {
        public double Invoke(int x, int y);
        // Other code
    }

As you can see using ILDASM.exe, the compiler generated operation class defines three public methods as follows:


Figure 1.1

After you have defined a delegate, you can create an instance of it so that you can use it to store details of a particular method.

Delegates Sample Program

The delegate implementation can cause a great deal of confusion when encountered first time. Thus, it an great idea to get an understanding by creating this sample program as:

using System;

namespace Delegates
{
    // Delegate Definition
    public delegate int operation(int x, int y);

    class Program
    {
        // Method that is passes as an Argument
        // It has same signature as Delegates
        static int Addition(int a, int b)
        {
            return a + b;
        }
        static void Main(string[] args)
        {
            // Delegate instantiation
            operation obj = new operation(Program.Addition);

            // output
            Console.WriteLine("Addition is={0}",obj(23,27));
            Console.ReadLine();
        }
    }
}

Here, we are defining the delegate with the delegate keyword. The important point is to remember the signature of the function reference by the delegate must match the delegate signature as:

// Delegate Definition
public delegate int operation(int x, int y);

Notice the format of operation delegate type declaration; it specifies that operation object can permit to any method taking two integers and returning an integer. When you want to insert the target methods to a given delegate object, simply pass in the name of the method to the delegate constructor as:

// Delegate instantiation
 operation obj = new operation(Program.Addition);

At this point, you are able to invoke the member pointed to using a direct function invocation as:

Console.WriteLine("Addition is={0}",obj(23,27));

Finally, when the delegate is no longer required, set the delegate instance to null.

Recall that .NET delegates are type-safe. Therefore, if you attempt to pass a delegate a method that does not match the pattern, the .NET returns a compile-time error.

Array of Delegates

Want to learn more?? The InfoSec Institute Web Application Penetration Testing Boot Camp focuses on preparing you for the real world of Web App Pen Testing through extensive lab exercises, thought provoking lectures led by an expert instructor. We review of the entire body of knowledge as it pertains to web application pen testing through a high-energy seminar approach.

The Web Application Penetration Testing course from InfoSec Institute is a totally hands-on learning experience. From the first day to the last day, you will learn the ins and outs of Web App Pen Testing by attending thought provoking lectures led by an expert instructor. Every lecture is directly followed up by a comprehensive lab exercise (we also set up and provide lab workstations so you don't waste valuable class time installing tools and apps). Benefits to you are:

  • Get CWAPT Certified
  • Learn the Secrets of Web App Pen Testing in a totally hands-on classroom environment
  • Learn how to exploit and defend real-world web apps: not just silly sample code
  • Complete the 83 Step "Web App Pen Test Methodology", and bring a copy back to work with you
  • Learn how perform OWASP Top 10 Assessments: for PCI DSS compliance

Creating an array of delegates is very similar to declaring array of any type. The following example has couple of static methods to perform specific math related operations. Then, you use delegates to call up these methods.

using System;

namespace Delegates
{
    public class Operation
    {
        public static void Add(int a, int b)
        {
            Console.WriteLine("Addition={0}",a + b);
        }
        public static void Multiple(int a, int b)
        {
            Console.WriteLine("Multiply={0}", a * b);
        }
    }
    class Program
    {
        delegate void DelOp(int x, int y);

        static void Main(string[] args)
        {
            // Delegate instantiation
            DelOp[] obj =
           {
               new DelOp(Operation.Add),
               new DelOp(Operation.Multiple)
           };

            for (int i = 0; i < obj.Length; i++)
            {
                obj[i](2, 5);
                obj[i](8, 5);
                obj[i](4, 6);
            }
            Console.ReadLine();
        }
    }
}

In this code, you instantiate an array of Delop delegates. Each element of the array is initialized to refer to a different operation implemented by the operation class. Then, you loop through the array, apply each operation to three different values. After compiling this code, the output would be as follows:


Figure 1.2

Anonymous Methods

Sometime a function is used with delegate. It never called directly as a stand-alone method. Anonymous methods are nameless methods. They prevent creating a separate method unnecessarily, which is a cleaner and more convenient approach.

Define an anonymous method with the delegate keyword and a nameless function body. This code assigns an anonymous method to the delegate. The anonymous method must not have a signature. The signature and return type is inferred from the delegate type. For example if the delegate has three parameters and returns a double type, then the anonymous method would also have the same signature.

using System;

namespace Delegates
{
    class Program
    {
        // Delegate Definition
        delegate void operation();

        static void Main(string[] args)
        {
            // Delegate instantiation
            operation obj = delegate
            {
                Console.WriteLine("Anonymous method");
            };
            obj();

            Console.ReadLine();
        }
    }
}

The anonymous methods reduce the complexity of code, especially where there are several events are defined. With the anonymous method, the code does not perform faster. The compiler still defines methods implicitly.

Multicast Delegate

So far, you have seen a single method calling with delegates. If you want to call more than one method, you need to make an explicit call through a delegate more than once. However, it is possible for a delegate to achieve such amazing functionality, which is referred to as multicast delegates.

The multicast delegate is similar to a virtual container where multiple functions reference where an invocation list is stored. It successively calls each method in FIFO order. When you wish to add a multiple method to a delegate object, you simply make use of overloaded += operator, rather than a direct assignment.

using System;

namespace Delegates
{
    public class Operation
    {
        public static void Add(int a)
        {
            Console.WriteLine("Addition={0}", a + 10);
        }
        public static void Square(int a)
        {
            Console.WriteLine("Multiple={0}",a *a);
        }
    }
    class Program
    {
        delegate void DelOp(int x);

        static void Main(string[] args)
        {
            // Delegate instantiation
            DelOp obj = Operation.Add;
            obj += Operation.Square;

            obj(2);
            obj(8);

            Console.ReadLine();
        }
    }
}

The above code combines two delegates that hold function Add() and Multiply(). Here the Add() method executes first and Multiply() later. This is the order in which the function pointers are added to the multicast delegates.

To remove function reference from a multicast delegate, use the overloaded -= operator that allows a caller to dynamically remove a method from the delegate object invocation lists. The following code provides an example:

// Delegate instantiation
DelOp obj = Operation.Add;
obj += Operation.Square;
obj -= Operation.Square;

Here when the delegate is invoked, the Add() method is executed but Multiply() is not because we unsubscribe it with the -= operator from a given runtime notification.

There might be a huge problem by invoking multiple methods by one delegate. If one of the methods invoked by a delegate throws an exception, then the complete iteration would be abort. You can avoid such scenario by iterating the list on your own. The Delegate class define the method GetInvocationList that return an array of Delegate objects.

using System;

namespace Delegates
{
    public class Operation
    {
        public static void one()
        {
            Console.WriteLine("one display");
            throw new Exception("Error");
        }
        public static void two()
        {
            Console.WriteLine("Two display");
        }
    }
    class Program
    {
        delegate void DelOp();

        static void Main(string[] args)
        {
            // Delegate instantiation
            DelOp obj = Operation.one;
            obj += Operation.two;

            Delegate[] del = obj.GetInvocationList();

            foreach (DelOp d in del)
            {
                try
                {
                    d();
                }
                catch (Exception)
                {
                    Console.WriteLine("Error caught");
                }
            }
            Console.ReadLine();
        }
    }
}

When you run the application, you can see that the iteration still continues with the next method, even after the exception is caught as follows:


Figure 1.3

Events

The application and windows are communicating by using predefined messages. These messages contain various pieces of information in order to determine both windows and application actions. .NET considers these messages as an event. If you need to react to a specific incoming message, you would handle the corresponding event. For instance, when you click a button over a form. Windows is sending a WM_MOUSECLICK message to the button message handler.

You don’t have to build custom methods to add or remove methods to a delegate invocation list. C# provides the event keyword. When the compiler processes the event keyword, you are automatically provided with registration and unregistration methods as well as any necessary member variable for your delegate types. The prototype for the event definition should be as follows:

Accessibility event delegatename eventname;

Defining an event is a two-step process. First, you need to define a delegate type that will hold the list of methods to be called when the event is fired. Next, you declare an event using the event keyword. To illustrate the event, we are creating a console application. In this iteration, we will define an event add which is associated to a single delegate DelEventHandler.

using System;

namespace Delegates
{
    public delegate void DelEventHandler();

    class Program
    {
        public static event DelEventHandler add;
        static void Main(string[] args)
        {
            add += new DelEventHandler(USA);
            add += new DelEventHandler(India);
            add += new DelEventHandler(England);
            add.Invoke();

            Console.ReadLine();
        }
        static void USA()
        {
            Console.WriteLine("USA");
        }
        static void India()
        {
            Console.WriteLine("India");
        }
        static void England()
        {
            Console.WriteLine("England");
        }
    }
}

In the main method, we associate the event with its corresponding event handler with function reference. We Here, we also filling the delegate invocation lists with couple of define methods using +=operator as well. Finally, we invoke the event via Invoke method to fire the event.

Note: Event Handlers can’t return a value. They always Void.

Let’s take another example to get a better understanding of events. Here, we are defining an event name as xyz and a delegate EventHandler with a string argument signature in the operation class. We are putting the implementation in action method to confirm whether an event is fired or not.

using System;

namespace Delegates
{
    public delegate void EventHandler(string a);

    public class Operation
    {
        public event EventHandler xyz;

        public void action(string a)
        {
            if (xyz != null)
            {
                xyz(a);
                Console.WriteLine(a);
            }
            else
            {
                Console.WriteLine("Not Registered");
            }
        }
    }

    class Program
    {
        public static void catch_event(string s)
        {
            Console.WriteLine("Method Calling");
        }
        static void Main(string[] args)
        {
            Operation o = new Operation();

            o.action("Event Calling");
            o.xyz += new EventHandler(catch_event);

            Console.ReadLine();
        }
    }
}

Later in the Program class, we are defining a catch_event method that would be referenced in the delegate invocation list. Finally, in the main method, we instantiated the operation class and put the event firing implementation.

Finally, we are elaborating events by given a realistic example of creating a custom button control over the windows form that would be called from a console application. First, we inherit the program class from the Form class and defined its associated namespace at the top. Thereafter, in the program class constructor, we are creating a custom button control.

using System;
using System.Drawing;
using System.Windows.Forms;

namespace Delegates
{
    //custom delegate
    public delegate void DelEventHandler();

    class Program :Form
    {
        //custom event
        public event DelEventHandler add;

        public Program()
        {
            // desing a button over form
            Button btn = new Button();
            btn.Parent = this;
            btn.Text = "Hit Me";
            btn.Location = new Point(100,100);

            //Event handler is assigned to
            // the button click event
            btn.Click += new EventHandler(onClcik);
            add += new DelEventHandler(Initiate);

            //invoke the event
            add();
        }
        //call when event is fired
        public void Initiate()
        {
            Console.WriteLine("Event Initiated");
        }

        //call when button clicked
        public void onClcik(object sender, EventArgs e)
        {
            MessageBox.Show("you clicked me");
        }
        static void Main(string[] args)
        {
            Application.Run(new Program());

            Console.ReadLine();
        }
    }
}

We are calling the Windows Form by using the Run method of the Application class. Finally when the user runs this application, first the Event fired message would be displayed on the screen and a Windows Form with custom button control. When the button clicked, a message box would be appeared as follows:

Figure 1.4