Delegates and Events

Delegates define reference types used for encapsulation of references to methods with a specific signature.

An instance of a delegate encapsulates an instance or static method. Delegates resemble C++ function pointers, except delegates are object-oriented, secure, and type-safe. Review delegate declaration syntax below:

[attributes] [modifiers] delegate result-type identifier ([formalparameters]);

Delegate declarations define types encapsulating methods with a specific set of arguments and return types. They have no awareness of or concern for the class of the object referenced. It uses any object as long as argument types and return types match the delegate, which provides anonymous invocation.

Instantiate a delegate (create the delegate object) with the new expression. In creation of the delegate, write the expression like a method call without arguments:

equipDB.ProcessNewEquipment(new ProcessNewEquipDelegate(PrintName));

Call a delegate by specifying its name, and arguments within parentheses:

processNewEquip(e);

Review an example of delegate use below:

using System;
delegate int ChangeNumber(int x);
namespace DelegateAppOne
{
	class DelegateTester
	{
		static int Anum = 9;
		public static int AddANum(int y)
		{
		Anum += y;
		return Anum;
		}

		public static int MultANum(int z)
		{
			Anum *= z;
			return Anum;
		}
		public static int getANum()
		{
			return Anum;
		}
		static void Main(string[] args)
		{
			//make delegate instances
			NumberChanger cnOne = new ChangeNumber(AddANum);
			NumberChanger cnTwo = new ChangeNumber(MultANum);

			//calling methods with delegate objects
			cnOne(22);
			Console.WriteLine("Number Value: {0}", getANum());
			cnTwo(4);
			Console.WriteLine("Number Value: {0}", getANum());
			Console.ReadKey();
		}
	}
}

Delegates allow for passing a function as a parameter. Type safety demands the function passed have a signature identical to the declaration.

Delegates consist of other delegates and serve as the base of an event.

DELEGATE TYPES

Two types of delegates exist: single and multicast. Single cast delegates only call one method at a time, and derive from System.Delegate. They hold a reference for a single method at any one time. Multicast delegates call multiple methods at once. They derive from System.MulticastDelegate. They hold an invocation list containing multiple methods.

DELEGATES AND INTERFACES

Delegates resemble interfaces due to the separation of specification and implementation, however, key differences make delegates a better choice in certain situations:

  1. When calling a single method
  2. When a class contains multiple implementations of the method specification
  3. When it makes sense to allow static method use for specification implementation
  4. When using an event-like design pattern
  5. When the caller does not need to be involved with the object from which the method is sourced
  6. When the implementation provider distributes the specification implementation only to select components
  7. When simple composition is needed

Interfaces prove more useful when the specification defines a group of related methods to call, a class implements the specification one time, or the interface caller will cast out or into the interface type to gather other interfaces or classes.

EVENTS

Events allow for the specification of a delegate call on the occurrence of an event. The delegate calls one or more associated methods when the event occurs such as a response to a mouse click. The class containing an event publishes the event; thus, it is known as the publisher. The class accepting this event is referred to as the subscriber class. The publisher object contains the event definition and the delegate, and it also defines the event-delegate relationship. The subscriber accepts the event and supplies the event handler. The delegate invokes the event handler (method) of the subscriber.

EVENT DEFINITION

Before defining an event, determine its associated delegate. Then, to define the event, create a class containing the delegate's event, a method for verification of the delegate declaration using the event keyword (optional), and methods calling the event. Define any classes connecting the event to methods. Each class contains associations with methods through the += and -= operators (event in the base class), and method definitions of associated methods.

Finally, employ the event by creating a class object containing the event declaration, and creating a class object containing the event definition using a developer-defined constructor. Review an example of a delegate and event below:

using System;
namespace TheEvent
{
	using System;
	public class EventTester
	{
		private int amount;
		public delegate void NumTweakHandler();
		public event NumTweakHandler AlterNum;
		protected virtual void OnNumAltered()
		{
			if (AlterNum != null) //invoke
			{
				AlterNum();
			}
			else
			{
				Console.WriteLine("Here's the event!");
			}
		}
		public EventTester(int x )
		{
			SetAmount(x);
		}
		public void SetAmount(int x)
		{
			if (value != x)
			{
				value = x;
				OnNumAltered();
			}
		}
	}
	public class TheMainClass
	{
		public static void Main()
		{
			EventTester e = new EventTester(6);
			e.SetAmount(8);
			e.SetAmount(12);
			Console.ReadKey();
		}
	}
}

EVENT INHERITANCE

Derived classes cannot directly perform event invocation due to event invocation only occurring from within its declaration class. However, derived classes can be granted invocation ability through creating a protected method for invocation. Calling the method allows derived classes to invoke. Making the method virtual further expands capability into overriding, which allows the derived class to intercept events invoked by the base class.