WTF is an Action Delegate?
Tags: csharp
Published: 2019-03-22 11:13:26

---
title: "WTF is an Action Delegate?"
published: true
description: How can you "swap in" different behaviours for a function? One way is to use C#'s Action Delegates
tags: csharp
cover_image: https://jonhilton.net/img/2019-02-07-what-are-action-func-delegates/2019-02-08-12-40-16.png
canonical_url: https://jonhilton.net/what-is-an-action-delegate/
---

In the last post we [explored what a lambda is](https://dev.to/jonhilt/wtf-is-a-lambda-2dg2), and what that weird `x=>x` syntax is all about.

Now we know *what* it is, you might be wondering *where* can you use them and how might you write your own code so that a lambda can be used.

The answer is delegates! 

Delegates act as a kind of placeholder for a method.

Let's take an example.

``` csharp
static void SaveToDatabase(Person person)
{
    try
    {
        // save here
    }
    catch (Exception)
    {
        Console.WriteLine("could not save");
    }
}
```

This method theoretically saves a person object. If something goes wrong, we catch the exception and log an error message to the console.

## Plug 'n' Play behaviour

Now imagine we're going to call this `SaveToDatabase` method from various places and want to be able to change how we log this message on a case by case basis. 

For example, instead of writing to console, sometimes we might choose to send an email instead.

One way to tackle this would be to make it possible for `SaveToDatabase` to take in a method which does the actual error logging. Then we can choose whether to pass in a method which writes to the console or a method which sends an email.

``` csharp
static void SaveToDatabase(Person person, Action onError)
{
    try
    {
        // save here
    }
    catch (Exception)
    {
        onError();
    }
}
```

`SaveToDatabase` now indicates that it expects to receive a method (`onError`).

The `Action` type here defines our `onError` argument as a delegate which takes zero arguments and doesn't return anything.

At this point `SaveToDatabase` doesn't know anything about what `onError` does, it merely knows its shape (a method with no arguments which returns void) and can "invoke" it whenever it likes, using this syntax...

``` csharp
onError();
```

This frees us up to pass in different methods when we call `SaveToDatabase`.

<center>
![](https://jonhilton.net/img/2019-02-07-what-are-action-func-delegates/2019-02-08-12-40-16.png)
</center>

Like so...

``` csharp
static void Main(string[] args)
{
    var person = new Person { Name = "bob" };
    SaveToDatabase(person, WriteErrorToConsole);
}

private static void WriteErrorToConsole()
{
    Console.WriteLine("Could not save");
}
```

Here we've created a method which takes no arguments and returns void (fulfilling the requirements for `onError`) and passed a reference to it along to `SaveToDatabase`.

Note we're not invoking `WriteErrorToConsole` in the `Main` method.

At no point do we do this...

``` csharp
WriteErrorToConsole()
```
Because that would immediately invoke the method and write a message to the console.

What we want is to pass that method along to `SaveToDatabase` which will invoke the method at a time of its own choosing.

Remember in the last post we discovered we can take a method like `WriteErrorToConsole` and "inline" it using lambdas?

We can do something very similar here...

``` csharp
static void Main(string[] args)
{
    var person = new Person { Name = "bob" };
    SaveToDatabase(person, ()=> Console.WriteLine("Could not save"));
}
```

We can't use `x=>x` because `onError` doesn't expect any arguments. Instead, we use empty parenthesis which serve the same purpose, but for Actions which take zero arguments.

## I want to say something else

What if we don't want to write "Could not save" to the console, but provide a more specific message (which varies depending on the actual error)?

For this we need to make our `onError` action accept some kind of error message...

``` csharp
catch (Exception ex)
{
    onError(ex.Message);
}
```
Whichever method gets passed in (the one which sends an email, or the one which writes to console) could make use of this message string and do with it as it pleases.

To make this work we need to tweak our declaration of the `onError` Action slightly.

``` csharp
static void SaveToDatabase(Person person, Action<string> onError)
{
    try
    {
        // save here
    }
    catch (Exception ex)
    {
        onError(ex.Message);
    }
}
```

Now we're using `Action<string>` which means we're expecting a method which takes a single string argument and returns void.

Our `Main` method can take that argument and use it when writing to the console.

``` csharp
static void Main(string[] args)
{
    var person = new Person { Name = "bob" };
    SaveToDatabase(person,
        message => Console.WriteLine($"Could not save, error: {message}"));
}
```

## Delegates delegates everywhere

As you've seen, delegates are pretty powerful and can be a great way to use the same function to do slightly different things depending on what delegate you pass in.

Here we've stuck to `Action` delegates but you can also use something called a `Func`.

More on that next time.