Delegates, Events and Lambda Expressions in C# – Part 3

C# .NET Built-In Delegates

All delegates discussed so far in this series are considered ‘custom’ delegates. The reason is that they are declared in the code are not part of a built-in .NET library. While custom delegates are useful and necessary at times, the .NET FCL library comes equipped with a number of built-in delegates that can be used in most scenarios and will help further reduce and simplify the code. The most two useful built-in delegates are Actions and Funcs.

Action
An Action in C# .NET is a generic void delegate that does not take-in any parameters. Using Actions will help reduce the amount of unnecessary code. All Action is a delegate declared in the System namespace. So if one desires to declare a parameterless void delegate, there is no need to declare a custom one. The Action delegate is perfectly suitable for the task. Below is the declaration of the Action delegate in the .NET library:

namespace System
{
    public delegate void Action();
}

Just like custom delegates, Actions can be assigned lambda expression, anonymous functions, delegates and methods. Actions can also be passed in as parameters to other functions.

Example using Actions

public class Program
{
     public static void Main(string[] args)
     {
          Action action = () => Console.WriteLine("Working");
          Run(action);
     }

     public static void Run(Action action)
     {
          action();
     }
}

Action
The .NET FCL library offers a generic version of Actions to support delegate parameters. Generic Actions work in the same way Actions do, except for the fact that each parameter type should be specified between the ‘<>‘ of the generic Action. The .NET FCL library supports any number of parameters. However, Actions are always void and never return a value. Below is the definition of Action in the ‘System’ namespace:

namespace System
{
    public delegate void Action<in T>(T obj);
}

Example Using Generic Actions
In the example below, an action with two integer parameters is declared and passed in to the ‘Run()’ method. In the same way Action is declared below, other Actions with more parameters can be declared. Using generic delegates in the example below saves one from declaring an explicit custom delegate since generic delegates can fulfill the same purpose.

public class Program
{
     public static void Main(string[] args)
     {
          Action<int, int> action = (a, b) => Console.WriteLine(a + b);
          Run(action);
     }

     public static void Run(Action<int, int> action)
     {
          action(2, 3);
     }
}


Func
Func is another type of built-in delegates available in the C# .NET library. It is similar to an Action. However, it is different that it supports return values. The last type specified in the Func’s generic parameters is always used for the return type. It is usually referred to as TResult. Func is a simple wrapper around a generic delegate declared in the System library:

namespace System
{
    public delegate TResult Func<in T, out TResult>(T arg);
}

An instance of Func can be created and initialized using other Func instances, other delegates or a Lambda Expression. Once executed, it will return a value like any other function in C#. Below is an example of a Func delegate that takes in an integer as an input parameter and returns an integer and a parameter. The Func is initialized using a simple Lambda Expression:

public class Program
{
     public static void Main(string[] args)
     {
          Func<int, int> func = (a) => a + 1;
          Run(func);
     }
      
     public static void Run(Func<int, int> func)
     {
          Console.WriteLine(func(2));
     }
}

It is important to note that the last parameter is always for the return type. So if a single parameter is used in the definition of a Func, then it is assumed that the function does not take in any input parameters and return a value. Below is an example of a function that returns the mathematical value of PI:

public class Program
{
     public static void Main(string[] args)
     {
          Func<double> getPI = () => Math.PI;
          PrintPI(getPI);
     }

     public static void PrintPI(Func<double> func)
     {
          Console.WriteLine(func());
     }
}

You may also like...

Leave a Reply

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