424

I'm relatively new in C#, & I'm wondering when to use Delegates appropriately. they are widely used in events declaration, but when should I use them in my own code and why are they useful? why not to use something else?

I'm also wondering when I have to use delegates and I have no other alternative.

Thank you for the help!

EDIT: I think I've found a necessary use of Delegates here

Mehdi Dehghani
  • 10,970
  • 6
  • 59
  • 64
iChaib
  • 469
  • 4
  • 10
  • 17
  • 8
    A Delegate is an object that knows how to call a method. {Definition from C# In a Nutshell} – GibboK Jun 11 '14 at 06:09
  • 1
    No it is not. That's just message forwarding. It isn't delegation. This is why there is so much confusion over delegation and events in C# - because there IS NO DELEGATION in C#. http://saturnflyer.com/blog/jim/2012/07/06/the-gang-of-four-is-wrong-and-you-dont-understand-delegation/ – Lloyd Sargent Nov 07 '14 at 18:13
  • 1
    From the tutorial: An event in C# is a way for a class to provide notifications ... (for example, click a button). Events are declared using delegates. Me: Therefore, you need Delegates to implement a listener in C#. That's it. MS has forced everyone into using Delegates for that. – Joe Cotton Aug 19 '16 at 20:05
  • Take a look at this article https://www.codeproject.com/Articles/85296/important-uses-of-Delegates-and-Events – NoWar Oct 03 '18 at 04:43
  • It's more like `delegate` in C# = function template in C++... – Yousha Aleayoub Jan 31 '20 at 16:56
  • You have to use the Delegates/Events when you need a low level of coupling ! => https://stackoverflow.com/a/61125090/2736742 – A. Morel Apr 09 '20 at 15:57
  • A delegate is a type for a method. – Michele Piccolini Oct 03 '20 at 15:42

8 Answers8

365

A delegate is a reference to a method. Whereas objects can easily be sent as parameters into methods, constructor or whatever, methods are a bit more tricky. But every once in a while you might feel the need to send a method as a parameter to another method, and that's when you'll need delegates.

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

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 };

      //Invoke DisplayPeople using appropriate delegate
      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;
    }
  }
}

Output:

Children:
Jake, 12 years old


Adults:
John, 41 years old
Jane, 69 years old
Jessie, 25 years old


Seniors:
Jane, 69 years old
Himanshu
  • 31,810
  • 31
  • 111
  • 133
dhaval8087
  • 1
  • 1
  • 2
  • 2
  • 17
    I like your delegate example, but I believe it would be more useful if you denoted the output using a comment, at the end. – Chef_Code Oct 25 '15 at 01:32
  • 3
    @dhaval8087 thanks for your answer - but where is it that methods are being added to the delegate? – BenKoshy Feb 15 '16 at 11:26
  • 4
    @BKSpurgeon this line static void DisplayPeople(string title, List people, FilterDelegate filter) this contains a FilterDelegate and DisplayPeople("Children:", people, IsChild) is what passing and finally within if() the delegate will call the method. – Zaker Feb 18 '16 at 07:28
  • @BKSpurgeon in the method `DisplayPeople()` the third argument is `FilterDelegate filter`. This basically says, put any argument here that matches the **signature** of `FilterDelegate`. In this case it is a method that returns bool and takes an argument of type `Person`. – BigHeadCreations Jul 29 '16 at 02:11
  • 5
    I think `IsChild()` should `return p.Age < 18`, not `p.Age <= 18`. As is, when `p.Age == 18`, both `IsChild()` and `IsAdult()` will return `true`. – cp.engr Sep 13 '16 at 15:44
  • 1
    The example will be even better, if you will show it without delegate :) Then you really can compare it. –  Jan 10 '20 at 13:06
339

I agree with everything that is said already, just trying to put some other words on it.

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.

davidsbro
  • 2,761
  • 4
  • 23
  • 33
Benoît Vidis
  • 3,908
  • 2
  • 23
  • 24
  • 3
    Personally, it feels to me that using delegates split up your code into units and make it tons more manageable. Great mechanism to use in conjunction with unit testing if most of your methods have the same signature pattern – Eon Jul 11 '14 at 11:22
  • 115
    "Please feel free to put any method that match this signature here and it will be called each time my delegate is called" -> you made my day, great explanation! – Gianluca Ghettini Sep 13 '14 at 14:42
  • 2
    Also consider it as runtime dynamic binding with many of the benefits of compile time static binding. Invocation of a delegate is orders of magnitude faster than the reflection invoke alternative. Additionally if a function signature changes such that it no longer matches the delegate this results in a compile time error which you don't get with reflection invoke. Consider for example the scenario of an MSMQ style message router. The Subscriber message receive functions could simply be stored in a dictionary of message routing key and subscriber delegate pair. – tcwicks Jan 31 '17 at 00:40
  • 5
    Are delegates considered a form of dependency injection? – DPM Mar 08 '19 at 01:46
157

Say you want to write a procedure to integrate some real-valued function f (x) over some interval [a, b]. Say we want to use the 3-Point Gaussian method to do this (any will do, of course).

Ideally we want some function that looks like:

// 'f' is the integrand we want to integrate over [a, b] with 'n' subintervals.
static double Gauss3(Integrand f, double a, double b, int n) {
  double res = 0;

  // compute result
  // ...

  return res;
}

So we can pass in any Integrand, f, and get its definite integral over the closed interval.

Just what type should Integrand be?

Without Delegates

Well, without delegates, we'd need some sort of interface with a single method, say eval declared as follows:

// Interface describing real-valued functions of one variable.
interface Integrand {
  double eval(double x);
}

Then we'd need to create a whole bunch of classes implementing this interface, as follows:

// Some function
class MyFunc1 : Integrand {
  public double eval(double x) {
    return /* some_result */ ;
  }
}

// Some other function
class MyFunc2 : Integrand {
  public double eval(double x) {
    return /* some_result */ ;
  }
}

// etc

Then to use them in our Gauss3 method, we need to invoke it as follows:

double res1 = Gauss3(new MyFunc1(), -1, 1, 16);
double res2 = Gauss3(new MyFunc2(), 0, Math.PI, 16);

And Gauss3 needs to do the look like the following:

static double Gauss3(Integrand f, double a, double b, int n) {
  // Use the integrand passed in:
  f.eval(x);
}

So we need to do all that just to use our arbitrary functions in Guass3.

With Delegates

public delegate double Integrand(double x);

Now we can define some static (or not) functions adhering to that prototype:

class Program {
   public delegate double Integrand(double x);   
   // Define implementations to above delegate 
   // with similar input and output types
   static double MyFunc1(double x) { /* ... */ }
   static double MyFunc2(double x) { /* ... */ }
   // ... etc ...

   public static double Gauss3(Integrand f, ...) { 
      // Now just call the function naturally, no f.eval() stuff.
      double a = f(x); 
      // ...
   }

   // Let's use it
   static void Main() {
     // Just pass the function in naturally (well, its reference).
     double res = Gauss3(MyFunc1, a, b, n);
     double res = Gauss3(MyFunc2, a, b, n);    
   }
}

No interfaces, no clunky .eval stuff, no object instantiation, just simple function-pointer like usage, for a simple task.

Of course, delegates are more than just function pointers under the hood, but that's a separate issue (function chaining and events).

Null Head
  • 2,877
  • 13
  • 61
  • 83
Alex Budovski
  • 17,947
  • 6
  • 53
  • 58
  • 8
    Why not simply use anonymous functions / lambdas then? – Pacerier Nov 05 '14 at 23:21
  • 2
    @Pacerier it's so that you can type check the inputted function. Anonymous functions don't have a type signature. – CMCDragonkai Nov 13 '14 at 03:02
  • 2
    Very good explanation, it helped me understand this better. There is a small "but": under the hood, there is object instantiation. `Gauss3(MyFunc1, a, b, n)` is a shorthand for `Gauss3(new Integrand(MyFunc1), a, b, n)`. – bgusach Nov 09 '15 at 08:15
  • @Alex thank you for your explanation. but why not just create a new type called Intergrand, rather than passing an interface called Intergrand? – BenKoshy Feb 14 '16 at 21:44
  • 1
    @BKSpurgeon Because you want different integrands? – Alex Budovski Feb 25 '16 at 05:10
34

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.

Pseudo:

function Retry(Delegate func, int numberOfTimes)
    try
    {
       func.Invoke();
    }
    catch { if(numberOfTimes blabla) func.Invoke(); etc. etc. }

Or when you want to do late evaluation of code blocks, like a function where you have some Transform action, and want to have a BeforeTransform and an AfterTransform action that you can evaluate within your Transform function, without having to know whether the BeginTransform is filled, or what it has to transform.

And of course when creating event handlers. You don't want to evaluate the code now, but only when needed, so you register a delegate that can be invoked when the event occurs.

Jan Jongboom
  • 26,598
  • 9
  • 83
  • 120
  • Additionally where you want the performance of early binding versus late binding. For example going through an application and replacing System Reflection Invoke with delegate calls. Delegate invocation is an order of magnitude faster than reflection invocation. Consider for example a message queue distributor pattern implementation. Subscribers to the message queue could receive work items via reflection invoke or via delegates. Via delegates provides far better performance. Additionally compile time error checking is a side benefit. – tcwicks Jan 31 '17 at 02:45
30

Delegates Overview

Delegates have the following properties:

  • Delegates are similar to C++ function pointers, but are type safe.
  • Delegates allow methods to be passed as parameters.
  • Delegates can be used to define callback methods.
  • Delegates can be chained together; for example, multiple methods can be called on a single event.
  • Methods don't need to match the delegate signature exactly. For more information, see Covariance and Contra variance.
  • C# version 2.0 introduces the concept of Anonymous Methods, which permit code blocks to be passed as parameters in place of a separately defined method.
Community
  • 1
  • 1
Lukas Šalkauskas
  • 14,191
  • 20
  • 61
  • 77
  • 4
    If you have a C++ then background thinking of them as function pointers is helpful. – James Bloomer Jan 07 '10 at 11:26
  • 3
    The biggest feature of delegates is that they combine a function pointer with an object that is of a type suitable for use with that function. The invoker of a delegate need not care what the delegate's "private data payload object" is--it's guaranteed to be the right type for the object. – supercat Dec 14 '10 at 06:14
28

I've just go my head around these, and so I'll share an example as you already have descriptions but at the moment one advantage I see is to get around the Circular Reference style warnings where you can't have 2 projects referencing each other.

Let's assume an application downloads an XML, and then saves the XML to a database.

I have 2 projects here which build my solution: FTP and a SaveDatabase.

So, our application starts by looking for any downloads and downloading the file(s) then it calls the SaveDatabase project.

Now, our application needs to notify the FTP site when a file is saved to the database by uploading a file with Meta data (ignore why, it's a request from the owner of the FTP site). The issue is at what point and how? We need a new method called NotifyFtpComplete() but in which of our projects should it be saved too - FTP or SaveDatabase? Logically, the code should live in our FTP project. But, this would mean our NotifyFtpComplete will have to be triggered or, it will have to wait until the save is complete, and then query the database to ensure it is in there. What we need to do is tell our SaveDatabase project to call the NotifyFtpComplete() method direct but we can't; we'd get a ciruclar reference and the NotifyFtpComplete() is a private method. What a shame, this would have worked. Well, it can.

During our application's code, we would have passed parameters between methods, but what if one of those parameters was the NotifyFtpComplete method. Yup, we pass the method, with all of the code inside as well. This would mean we could execute the method at any point, from any project. Well, this is what the delegate is. This means, we can pass the NotifyFtpComplete() method as a parameter to our SaveDatabase() class. At the point it saves, it simply executes the delegate.

See if this crude example helps (pseudo code). We will also assume that the application starts with the Begin() method of the FTP class.

class FTP
{
    public void Begin()
    {
        string filePath = DownloadFileFromFtpAndReturnPathName();

        SaveDatabase sd = new SaveDatabase();
        sd.Begin(filePath, NotifyFtpComplete());
    }

    private void NotifyFtpComplete()
    {
        //Code to send file to FTP site
    }
}


class SaveDatabase
{
    private void Begin(string filePath, delegateType NotifyJobComplete())
    {
        SaveToTheDatabase(filePath);

        /* InvokeTheDelegate - 
         * here we can execute the NotifyJobComplete
         * method at our preferred moment in the application,
         * despite the method being private and belonging
         * to a different class.
         */
        NotifyJobComplete.Invoke();
    }
}

So, with that explained, we can do it for real now with this Console Application using C#

using System;

namespace ConsoleApplication1
{
    /* I've made this class private to demonstrate that 
    * the SaveToDatabase cannot have any knowledge of this Program class.
    */
    class Program
    {
        static void Main(string[] args)
        {
            //Note, this NotifyDelegate type is defined in the SaveToDatabase project
            NotifyDelegate nofityDelegate = new NotifyDelegate(NotifyIfComplete);

            SaveToDatabase sd = new SaveToDatabase();            
            sd.Start(nofityDelegate);
            Console.ReadKey();
        }

        /* this is the method which will be delegated -
         * the only thing it has in common with the NofityDelegate
         * is that it takes 0 parameters and that it returns void.
         * However, it is these 2 which are essential.
         * It is really important to notice that it writes
         * a variable which, due to no constructor,
         * has not yet been called (so _notice is not initialized yet).
         */ 
    private static void NotifyIfComplete()
    {
        Console.WriteLine(_notice);
    }

    private static string _notice = "Notified";
    }


    public class SaveToDatabase
    {
        public void Start(NotifyDelegate nd)
        {
            /* I shouldn't write to the console from here, 
             * just for demonstration purposes
             */
            Console.WriteLine("SaveToDatabase Complete");
            Console.WriteLine(" ");
            nd.Invoke();
        }
    }
    public delegate void NotifyDelegate();
}

I suggest you step through the code and see when _notice is called and when the method (delegate) is called as this, I hope, will make things very clear.

However, lastly, we can make it more useful by changing the delegate type to include a parameter.

using System.Text;

namespace ConsoleApplication1
{
    /* I've made this class private to demonstrate that the SaveToDatabase
     * cannot have any knowledge of this Program class.
     */
    class Program
    {
        static void Main(string[] args)
        {
            SaveToDatabase sd = new SaveToDatabase();
            /* Please note, that although NotifyIfComplete()
         * takes a string parameter, we do not declare it,
         * all we want to do is tell C# where the method is
         * so it can be referenced later,
         * we will pass the parameter later.
         */
            var notifyDelegateWithMessage = new NotifyDelegateWithMessage(NotifyIfComplete);

            sd.Start(notifyDelegateWithMessage );

            Console.ReadKey();
        }

        private static void NotifyIfComplete(string message)
        {
            Console.WriteLine(message);
        }
    }


    public class SaveToDatabase
    {
        public void Start(NotifyDelegateWithMessage nd)
        {
                        /* To simulate a saving fail or success, I'm just going
         * to check the current time (well, the seconds) and
         * store the value as variable.
         */
            string message = string.Empty;
            if (DateTime.Now.Second > 30)
                message = "Saved";
            else
                message = "Failed";

            //It is at this point we pass the parameter to our method.
            nd.Invoke(message);
        }
    }

    public delegate void NotifyDelegateWithMessage(string message);
}
Hoshani
  • 746
  • 1
  • 10
  • 27
Dave
  • 8,163
  • 11
  • 67
  • 103
  • Dave, in your example, what is the difference, if any, between using a delegate vs making _NotifyIfComplete_ internal/public and call _Program.NotifyIfComplete_ directly, since _NotifyIfComplete_ is a static method? – PersyJack Feb 06 '15 at 15:21
  • 1
    @PersyJack When you pass a delegate as a parameter then your method trusts that a suitable delegate is passed and your method has no understanding of the delegate's value/logic- it is decoupled. My `Start` method has no idea of anything other than what is passed to it. If I added a static method, then my `Start` method has to know about this static class and the method! I could also pass a delegate which actually doesn't pass NotifyIfComplete but passes my EmailCustomer or SaveToDatabase function. – Dave Feb 06 '15 at 15:39
  • Dave, thank you, I was just confused about the difference between passing a delegate vs calling a static method, but your explanation and this [article](https://msdn.microsoft.com/en-us/library/aa288459%28v=vs.71%29.aspx) made it clear. – PersyJack Feb 06 '15 at 15:43
12

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.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
4

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.

While it could be possible to create an extensive set of code to perform this functionality, you don’t need too. You can use a delegate.

Creating a delegate is easy to do. Identify the class as a delegate with the "delegate" keyword. Then specify the signature of the type.

Pankaj
  • 4,419
  • 16
  • 50
  • 72
  • A delegate is a type safe function pointer.That is, they hold reference(Pointer) to a function. The signature of the delegate must match the signature of the function, the delegate points to, otherwise you get a compiler error. This is the reason delegates are called as type safe function pointers. A Delegate is similar to a class. You can create an instance of it, and when you do so, you pass in the function name as a parameter to the delegate constructor, and it is to this function the delegate will point to. – Vivek Shukla Aug 08 '17 at 15:11