C# Delegates :Types and usage
Published: 2023-11-02 22:51:20

If you are in the process of learning or developing in C#, you will certainly stumble upon cases of passing a method as a parameter, all while applying programming concepts such as polling, callbacks, and techniques such as Linq. In this case, you certainly worked with the C# delegates. In this article we'll delve into the details of this concept for a better understanding.

To download the source code for this article, you can visit our GitHub repository.

**Delegates Declarartion :**
In C#, delegates represent a reference type that points to a method with a specific signature. They can be declared within a class or independently, as shown in the code below:

```
namespace DelegatesDemo.DelegateAppl {
    public delegate string FirstDelegate (int x);
    public class Sample {
        public delegate void SecondDelegate (char a, char b);
    }
}
```

Let's instantiate some delegates and use them to refer methods:

```
namespace DelegatesDemo.DelegateAppl
{
    delegate int ValueSubstitute(int n);
    public static class DelegateDemo
    {
        delegate int ValueUpdate(int n);
        static int Value = 10;
        public static int CurrentValue()
        {
            return Value;
        }
        public static int SumOperation(int p)
        {
            Value += p;
            return Value;
        }
        public static int MultOperation(int q)
        {
            Value *= q;
            return Value;
        }
        public static void RunDelegate()
        {
            ValueUpdate update1 = new ValueUpdate(SumOperation);
            ValueUpdate update2 = new ValueUpdate(MultOperation);


            update1(25);
            Console.WriteLine("Value of Num: {0}", CurrentValue());
            update2(5);
            Console.WriteLine("Value of Num: {0}", CurrentValue());
            Console.ReadKey();
        }
    }
}
```
We defined two instances of the ValueUpdate delegate. The first delegate is used to get two integers' sum. The second delegate represents the multiplication operation of two integers.
Delegates allow developers to handle methods the same as objects, passing them as parameters, invoking them dynamically, and assigning them to variables. With all these usage scenarios, Microsoft took it a step further providing more specific types of delegates, the Func, Action, and Predicate.
**C# Func:**

Func represents the delegates that could take one or multiple Input parameters, and return a value. Its declaration depends on the number of parameters the referenced method could take :

- Case of  no input parameter : Func<TResult> 
- Case of one input parameter: Func<T1, TResult>
- Case of two input parameters: Func<T1, T2, Tresult>

The Func delegate in C# could take up to 16 input parameters, besides the TResult which represents the return type of the referenced method, and it does not allow ref and out parameters.

Below, we define and make use of a couple of Funcs:

```
public static Func<int, int, int> intMultiplyFunc = delegate (int a, int b)
{
    return a * b;
};

int intMultResult = intMultiplyFunc(15, 1);
Console.WriteLine(intMultResult);
```

This example shows the usage of a Func with an anonymous method, which takes two integers and returns their multiplication result.

The next example shows the usage of a Func with a lambda function that takes two integers and returns their sum:

```
Func<int, int, int> intSumFunc = (a, b) => a + b;
int intSumResult = intSumFunc(5, 3);
Console.WriteLine(intSumResult);
```
**C# Action:**

Similar to the Func concept, Action is a built-in generic delegate that represents one or many methods. It could be defined with an anonymous or lambda function. However, it is limited to methods with no specific return type. It only represents a method with the return type set to void.
We'll define an example of Action that is representing an anonymous method :

```
Action<string> displayName = delegate (string name)
{
    name = name.ToUpper();
    Console.WriteLine($"Hello, {name}!");
};

displayName("Code Maze");
```

The displayName delegate in this case takes a string as an argument and makes use of it as per the user requirements: Converting it to uppercase and displaying it. The logic in this case is in the form of an anonymous method, which is a convenient way to write logic that is rather short and not redundant throughout our application.

**C# Predicate:**

Getting more specific with delegates, Predicates is the delegate representing a method that takes only one input parameter and returns only a boolean type. It is useful when defining a couple of conditions to be checked against the input parameter and returns a boolean value representing whether those criterias were met or not.
Below is an example of a predicate that represents a classic C# method:

```
static bool IsLowerCase(string str)
{
    return str.Equals(str.ToLower());
}
public static void RunPredicate()
{
    Predicate<string> isUpper = IsLowerCase;


    bool result = isUpper("hello world!!");
    Console.WriteLine(result);
    Console.ReadKey();
}
```

This Predicate example checks whether a provided string parameter is lowercase or not. As mentioned, it takes only one parameter(string type in this case) and returns a boolean value. It is worth noting that predicates could also be defined using anonymous and Lambda expressions.

**Conclusion:**

In this article, we delved into one of the most useful C# aspects: delegates. Covering its various types along with examples to help illustrate and clarify the concept. You will need this technique, especially with Linq, implementing design patterns such as Observer, Strategy, and Visitor or writing functional code in C#.