Codementor Events

Beginner's Guide to Delegates, Funcs and Actions in C#

Published Apr 22, 2016Last updated Apr 14, 2017
Beginner's Guide to Delegates, Funcs and Actions in C#

In this tutorial, I'll be giving a short introduction to delegates in C#.

So, what's a delegate?

In the same fashion that a class is a reference type that holds references to objects, delegates are also reference types, except they hold references to other methods.

To put it even more plainly, classes are to objects what delegates are to methods.

When you look at it from that perspective, they're actually not that different, both classes and delegates are declared in similar fashion and both of them are reference types.

The class reference type vs delegate reference type


Types of delegates

There's a number of different types of delegates that we will be covering:

  1. The Delegate type
  2. The Action type
  3. The Func type

The Delegate type

Declaration

The delegate type is declared by using the type name delegate, followed by the return type, name of the delegate and its input parameters.

// Structure of a delegate
delegate  <return.type>   <name>   (<type.parameter>)

// Example
delegate string Foo (int value);

To reference a method to a delegate, the signature of both the delegate and method must match completely so:

  • Return types must be the same.
  • Input parameters must also be the same (and in matching order).

Example

Below we're referencing the Bar method to the Foo delegate.

void Main()
{
    Foo fooExample = Bar;
    string time = fooExample(DateTime.UtcNow);
    Console.WriteLine (time);
}

public delegate string Foo (DateTime time);

public string Bar(DateTime value)
{
    return value.ToString("t");
}

Example 2 - Multicasting

Multiple delegate objects can be combined into a single instance, and it's the combination of delegates under that instance that becomes a Multicast delegate.

When the multicast delegates are invoked, they iterate through their list of delegates and invoke them in order.

Carrying on from the example above.

void Main()
{
    var now = DateTime.UtcNow;
    Foo fooTime, 
        fooDate, 
        fooMulticast;
        
    fooTime = BarTime;
    fooDate = BarDate;
    
    fooMulticast = fooTime + fooDate;
    
    
    Console.Write("FooTime: \n----\n");
    fooTime(now);
    Console.WriteLine ();
   
   /* - OUTPUT
        FooTime: 
        ----
        04:23
    */
    
    
    Console.Write("FooDate: \n----\n");
    fooDate(now);
    Console.WriteLine ();
   
   /* - OUTPUT
        FooDate: 
        ----
        21/04/2016
    */

    
    
    Console.Write("FooMulticast: \n----\n");
    fooMulticast(now);
  
   /* - OUTPUT
        FooMulticast: 
        ----
        04:23
        21/04/2016
    */
}

public delegate string Foo (DateTime time);

public string BarTime(DateTime value)
{   
    var str = value.ToString("t");
    Console.WriteLine ("{0}",str);
    
    return str;
}

public string BarDate(DateTime value)
{
    var str = value.ToString("dd/MM/yyyy");
    Console.WriteLine ("{0}",str);
    
    return str;
}

The Action delegate

The Action Delegate is a delegate which has a return type of void. The parameters of the action delegate are set using type parameters.

void Example()
{
    // Named method
    this.NamedActionDelegate = NamedMethod;
    this.NamedActionDelegate.Invoke("Hi", 5);
    // Output > Named said: Hi 5

    // Anonymous Function > Lambda
    this.AnonymousActionDelegate.Invoke("Foooo", 106);
    // Output > Anonymous said: Foooo 106
}

public Action<string, int> NamedActionDelegate { get; set; }
public Action<string, int> AnonymousActionDelegate = (text, digit) => Console.WriteLine ("Anonymous said: {0} {1}", text, digit);

public void NamedMethod(string text, int digit)
{
    Console.WriteLine ("Named said: {0} {1}", text, digit);
}

The Func delegate

The Func Delegate is similar to the Action Delegate, the difference being that Func can never return void, it will always require at least one type argument. As mentioned earlier, the type argument specified last dictates the return type of the delegate.

void Example()
{
    // Named method
    this.NamedFuncDelegate = NamedMethod;
    string namedResult = this.NamedFuncDelegate.Invoke(5);
    Console.WriteLine (namedResult);
    // Output > Named said: 5

    // Anonymous Function > Lambda
    string anonyResult = this.AnonymousFuncDelegate.Invoke(106);
    Console.WriteLine (anonyResult);
    // Output > Anonymous said: 106
}

public Func<int, string> NamedFuncDelegate { get; set; }
public Func<int, string> AnonymousFuncDelegate = (digit) => { return string.Format("Anonymous said: {0}", digit); };

public string NamedMethod(int digit)
{
    return string.Format ("Named said: {0}", digit);
}
Discover and read more posts from Aydin Fatih
get started
post commentsBe the first to share your opinion
אורי גרוס
6 years ago

Hi, thank you for this nice website. Please add the fact that Action & Function can accept up to 16 Arguments

Parthiban Sekar
6 years ago

Also, a question:

        List<Print> MyDelegates = new List<Print>();

        for (int i = 0; i < 9; i++)
        {
            MyDelegates.Add((x) => { Console.WriteLine("Print -> {0}", i); });
        }

        foreach (var MyDelegate in MyDelegates)
        {
            MyDelegate(1);
        }

Why the output is always 9 and not 0-8 for all 9 methods? If you can help with this one, please!

Cheers!

Aydin Fatih
6 years ago

The issue is that you’re directly referencing the variable i, not the value of i.

The value of i starts off at 0, but it’s assigned new values on each iteration and the old value is discarded. You may be thinking, “but an integer is a value type, wouldn’t it just reference the value of the integer”.

Not exactly, Jon Skeet elaborates pretty well into the why’s.

To fix your issue, you need to declare a copy of i and use the copy instead of i. Here’s how

    for (int i = 0; i < 9; i++)
    {
        var iTemp = i;
        MyDelegates.Add((x) => { Console.WriteLine("Print -> {0}", iTemp); });
    }
Parthiban Sekar
6 years ago

Thanks for clarifying that. Much appreciated.

Parthiban Sekar
6 years ago

This is wonderful! Thanks much. Could you elaborate on the difference between Action and Func types, please?

Aydin Fatih
6 years ago

Action types are methods that have a return type of void.

Func types are methods that never return void.

Both can accept an arbtitrary number of parameters, the key difference between them is that one returns void, whilst the other always has a return type and can never return void.

Parthiban Sekar
6 years ago

Thanks much!

Show more replies