Why and when use Delegate

Why and when use Delegate

A delegate is an object that knows how to call a method.

A delegate can be seen as a placeholder for a/some method(s).

By defining a delegate, you are saying to the user of your class, “Please feel free to assign, any method that matches this signature, to the delegate and it will be called each time my delegate is called“.

Typical use is of course events. All the OnEventX delegate to the methods the user defines.

Delegates are useful to offer to the user of your objects some ability to customize their behavior. Most of the time, you can use other ways to achieve the same purpose and I do not believe you can ever be forced to create delegates. It is just the easiest way in some situations to get the thing done.

A delegate is a simple class that is used to point to methods with a specific signature, becoming essentially a type-safe function pointer. A delegate’s purpose is to facilitate a call back to another method (or methods), after one has been completed, in a structured way.

A delegate instance literally acts as a delegate for the caller: the caller invokes the delegate, and then the delegate calls the target method. This indirection decouples the caller from the target method.

General Scenario

When a head of state dies, the President of the United States typically does not have time to attend the funeral personally. Instead, he dispatches a delegate. Often this delegate is the Vice President, but sometimes the VP is unavailable and the President must send someone else, such as the Secretary of State or even the First Lady. He does not want to “hardwire” his delegated authority to a single person; he might delegate this responsibility to anyone who is able to execute the correct international protocol.

The President defines in advance what responsibility will be delegated (attend the funeral), what parameters will be passed (condolences, kind words), and what value he hopes to get back (good will). He then assigns a particular person to that delegated responsibility at “runtime” as the course of his presidency progresses.

In programming Scenario

You are often faced with situations where you need to execute a particular action, but you don’t know in advance which method, or even which object, you’ll want to call upon to execute it.

For Example

A button might not know which object or objects need to be notified. Rather than wiring the button to a particular object, you will connect the button to a delegate and then resolve that delegate to a particular method when the program executes.

Another good example is the ‘Where’ function, one of the standard linq methods. ‘Where’ takes a list and a filter, and returns a list of the items matching the filter. (The filter argument is a delegate which takes a T and returns a boolean.)

Because it uses a delegate to specify the filter, the Where function is extremely flexible. You don’t need different Where functions to filter odd numbers and prime numbers, for example. The calling syntax is also very concise, which would not be the case if you used an interface or an abstract class.

More concretely, Where taking a delegate means you can write this:

 

var result = list.Where(x => x != null);
 ...

instead of this:

var result = new List<T>();
 foreach (var e in list)
    if (e != null)
       result.add(e)
 ...

WHEN

  • I consider delegates to be Anonymous Interfaces. In many cases you can use them whenever you need an interface with a single method, but you don’t want the overhead of defining that interface.
  • Delegates are extremely useful when wanting to declare a block of code that you want to pass around. For example when using a generic retry mechanism.

 

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

namespace DelegateApp {

/// <summary>
 /// A class to define a person
 /// </summary>
 public class Person {
 public string Name { get; set; }
 public int Age { get; set; }
 }

class Program {
 //Our delegate
 public delegate bool FilterDelegate(Person p);

static void Main(string[] args) {

//Create 4 Person objects
 Person p1 = new Person() { Name = "John", Age = 41 };
 Person p2 = new Person() { Name = "Jane", Age = 69 };
 Person p3 = new Person() { Name = "Jake", Age = 12 };
 Person p4 = new Person() { Name = "Jessie", Age = 25 };

//Create a list of Person objects and fill it
 List<Person> people = new List<Person>() { p1, p2, p3, p4 };
 DisplayPeople("Children:", people, IsChild);
 DisplayPeople("Adults:", people, IsAdult);
 DisplayPeople("Seniors:", people, IsSenior);

Console.Read();
 }

/// <summary>
 /// A method to filter out the people you need
 /// </summary>
 /// <param name="people">A list of people</param>
 /// <param name="filter">A filter</param>
 /// <returns>A filtered list</returns>
 static void DisplayPeople(string title, List<Person> people, FilterDelegate filter) {
 Console.WriteLine(title);

foreach (Person p in people) {
 if (filter(p)) {
 Console.WriteLine("{0}, {1} years old", p.Name, p.Age);
 }
 }

Console.Write("\n\n");
 }

//==========FILTERS===================
 static bool IsChild(Person p) {
 return p.Age <= 18;
 }

static bool IsAdult(Person p) {
 return p.Age >= 18;
 }

static bool IsSenior(Person p) {
 return p.Age >= 65;
 }
 }
 }

 

Share

Leave a Reply

Your email address will not be published. Required fields are marked *