---
title: "5 useful extensions for Task<T> in .NET"
description: "In this short blog post, I will show you 5 useful extensions for Task<T> in .NET. We will build them as extension methods, so there are easy to use.\nOn top, I will show a small example of how to use them. So let's go!"
updated: 2023-04-10
tags: ["async", ".NET", "await", "Task", "C#"]
canonical: "https://steven-giesel.com/blogPost/d38e70b4-6f36-41ff-8011-b0b0d1f54f6e/5-useful-extensions-for-taskt-in-net"
---

# 5 useful extensions for Task<T> in .NET

In this short blog post, I will show you 5 useful extensions for Task<T> in .NET. We will build them as extension methods, so there are easy to use.
On top, I will show a small example of how to use them. So let's go!

## 1. Fire and forget
Sometimes you want to fire and forget a task. This means that you want to start a task but you don't want to wait for it to finish. This is useful when you want to start a task but you don't care about the result (non-critical tasks). For example when you want to start a task that sends an email. You don't want to wait for the email to be sent before you can continue with your code. So you can use the `FireAndForget` extension method to start the task and forget about it. Optionally you can pass an error handler to the method. This error handler will be called when the task throws an exception.

```csharp
public static void FireAndForget(
  this Task task,
  Action<Exception> errorHandler = null)
{
    task.ContinueWith(t =>
    {
        if (t.IsFaulted && errorHandler != null)
            errorHandler(t.Exception);
    }, TaskContinuationOptions.OnlyOnFaulted);
}
```

Usage:

```csharp
SendEmailAsync().FireAndForget(errorHandler => Console.WriteLine(errorHandler.Message));
```

## 2. Retry
If you want to retry a task a specific number of times, you can use the `Retry` extension method. This method will retry the task until it succeeds or the maximum number of retries is reached. You can pass a delay between retries. This delay will be used between each retry.

```csharp
public static async Task<TResult> Retry<TResult>(this Func<Task<TResult>> taskFactory, int maxRetries, TimeSpan delay)
{
    for (int i = 0; i < maxRetries; i++)
    {
        try
        {
            return await taskFactory().ConfigureAwait(false);
        }
        catch
        {
            if (i == maxRetries - 1)
                throw;
            await Task.Delay(delay).ConfigureAwait(false);
        }
    }

    return default(TResult); // Should not be reached
}
```

Usage:

```csharp
var result = await (() => GetResultAsync()).Retry(3, TimeSpan.FromSeconds(1));
```

## 3. `OnFailure`
Executes a callback function when a Task encounters an exception.

```csharp
public static async Task OnFailure(this Task task, Action<Exception> onFailure)
{
    try
    {
        await task.ConfigureAwait(false);
    }
    catch (Exception ex)
    {
        onFailure(ex);
    }
}
```

Usage:

```csharp
await GetResultAsync().OnFailure(ex => Console.WriteLine(ex.Message));
```

## 4. Timeout
Sometimes you want to set a timeout for a task. This is useful when you want to prevent a task from running for too long. You can use the `Timeout` extension method to set a timeout for a task. If the task takes longer than the timeout the task will be cancelled.

```csharp
public static async Task WithTimeout(this Task task, TimeSpan timeout)
{
    var delayTask = Task.Delay(timeout);
    var completedTask = await Task.WhenAny(task, delayTask).ConfigureAwait(false);
    if (completedTask == delayTask)
        throw new TimeoutException();

    await task;
}
```

Usage:

```csharp
await GetResultAsync().WithTimeout(TimeSpan.FromSeconds(1));
```

**Note**: Since .NET 6 you can use [`WaitAsync`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.waitasync?view=net-7.0#system-threading-tasks-task-waitasync(system-timespan)).

## 5. Fallback
Sometimes you want to use a fallback value when a task fails. You can use the `Fallback` extension method to use a fallback value when a task fails.

```csharp
public static async Task<TResult> Fallback<TResult>(this Task<TResult> task, TResult fallbackValue)
{
    try
    {
        return await task.ConfigureAwait(false);
    }
    catch
    {
        return fallbackValue;
    }
}
```

Usage:

```csharp
var result = await GetResultAsync().Fallback("fallback");
```

## Conclusion
There we have it: Five useful extensions for Task<T>. Of course, you can also make them work for `ValueTask` if you want to. If you have more, please let me know!