Created
October 24, 2023 15:02
-
-
Save d1820/7bfc043d12328c4214608f86038b4d3a to your computer and use it in GitHub Desktop.
.Net Task Extensions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// we use this to group them all as available based on already using this namespace | |
namespace Common.Extensions | |
{ | |
/// <summary> | |
/// adapted from https://archive.ph/2022.10.14-213608/https://betterprogramming.pub/my-top-7-custom-extension-methods-for-net-7-and-c-494acb2e6634#selection-1935.0-2339.1 | |
/// </summary> | |
public static class TaskExtensions | |
{ | |
/// <summary> | |
/// Wraps the executing task in a try/catch | |
/// </summary> | |
/// <param name="task"> The task. </param> | |
/// <param name="errorHandler"> The error handler. </param> | |
/// <param name="rethrow"> If true, rethrow. </param> | |
/// <returns> A Task. </returns> | |
public static async Task TryAsync(this Task task, Action<Exception>? errorHandler = null, bool rethrow = false) | |
{ | |
try | |
{ | |
await task; | |
} | |
catch (Exception ex) | |
{ | |
errorHandler?.Invoke(ex); | |
if (rethrow) | |
{ | |
throw; | |
} | |
} | |
} | |
/// <summary> | |
/// Wraps the executing task in a try/catch | |
/// </summary> | |
/// <typeparam name="T"> </typeparam> | |
/// <param name="task"> The task. </param> | |
/// <param name="errorHandler"> The error handler. </param> | |
/// <param name="rethrow"> If true, rethrow. </param> | |
/// <returns> <![CDATA[Task<T>]]> </returns> | |
public static async Task<T?> TryAsync<T>(this Task<T?> task, Action<Exception>? errorHandler = null, bool rethrow = false) where T : class | |
{ | |
try | |
{ | |
return await task; | |
} | |
catch (Exception ex) | |
{ | |
errorHandler?.Invoke(ex); | |
if (rethrow) | |
{ | |
throw; | |
} | |
} | |
return default; | |
} | |
/// <summary> | |
/// Returns when all tasks are completed asynchronously. | |
/// </summary> | |
/// <typeparam name="T"> </typeparam> | |
/// <param name="tasks"> The tasks. </param> | |
/// <exception cref="ArgumentNullException"> </exception> | |
/// <returns> <![CDATA[Task<IEnumerable<T>>]]> </returns> | |
public static async Task<IEnumerable<T>> WhenAllAsync<T>(this IEnumerable<Task<T>> tasks) | |
{ | |
if (tasks is null) | |
{ | |
throw new ArgumentNullException(nameof(tasks)); | |
} | |
return await Task | |
.WhenAll(tasks) | |
.ConfigureAwait(false); | |
} | |
/// <summary> | |
/// Returns when all tasks are completed asynchronously. | |
/// </summary> | |
/// <param name="tasks"> The tasks. </param> | |
/// <exception cref="ArgumentNullException"> </exception> | |
/// <returns> A Task. </returns> | |
public static Task WhenAllAsync(this IEnumerable<Task> tasks) | |
{ | |
if (tasks is null) | |
{ | |
throw new ArgumentNullException(nameof(tasks)); | |
} | |
return Task | |
.WhenAll(tasks); | |
} | |
/// <summary> | |
/// Returns when all tasks are completed in sequentially asynchronously. | |
/// </summary> | |
/// <typeparam name="T"> </typeparam> | |
/// <param name="tasks"> The tasks. </param> | |
/// <exception cref="ArgumentNullException"> </exception> | |
/// <returns> <![CDATA[Task<IEnumerable<T>>]]> </returns> | |
public static async Task<IEnumerable<T>> WhenAllSequentialAsync<T>(this IEnumerable<Task<T>> tasks) | |
{ | |
if (tasks is null) | |
{ | |
throw new ArgumentNullException(nameof(tasks)); | |
} | |
var results = new List<T>(); | |
foreach (var task in tasks) | |
{ | |
results.Add(await task.ConfigureAwait(false)); | |
} | |
return results; | |
} | |
/// <summary> | |
/// Returns when all tasks are completed in sequentially asynchronously. | |
/// </summary> | |
/// <param name="tasks"> The tasks. </param> | |
/// <exception cref="ArgumentNullException"> </exception> | |
/// <returns> A Task. </returns> | |
public static async Task WhenAllSequentialAsync(this IEnumerable<Task> tasks) | |
{ | |
if (tasks is null) | |
{ | |
throw new ArgumentNullException(nameof(tasks)); | |
} | |
foreach (var task in tasks) | |
{ | |
await task.ConfigureAwait(false); | |
} | |
} | |
/// <summary> | |
/// Returns when all tasks are completed in parallel asynchronously. | |
/// </summary> | |
/// <typeparam name="T"> </typeparam> | |
/// <param name="tasks"> The tasks. </param> | |
/// <param name="maxDegreeOfParallelism"> The degree. </param> | |
/// <exception cref="ArgumentNullException"> </exception> | |
/// <returns> <![CDATA[Task<IEnumerable<T>>]]> </returns> | |
public static async Task<IEnumerable<T>> WhenAllParallelAsync<T>(this IEnumerable<Task<T>> tasks, int maxDegreeOfParallelism) | |
{ | |
if (tasks is null) | |
{ | |
throw new ArgumentNullException(nameof(tasks)); | |
} | |
var results = new List<T>(); | |
foreach (var chunk in tasks.Chunk(maxDegreeOfParallelism)) | |
{ | |
var chunkResults = await Task.WhenAll(chunk).ConfigureAwait(false); | |
results.AddRange(chunkResults); | |
} | |
return results; | |
} | |
/// <summary> | |
/// Returns when all tasks are completed in parallel asynchronously. | |
/// </summary> | |
/// <param name="tasks"> The tasks. </param> | |
/// <param name="maxDegreeOfParallelism"> The degree. </param> | |
/// <exception cref="ArgumentNullException"> </exception> | |
/// <returns> A Task. </returns> | |
public static async Task WhenAllParallelAsync(this IEnumerable<Task> tasks, int maxDegreeOfParallelism) | |
{ | |
if (tasks is null) | |
{ | |
throw new ArgumentNullException(nameof(tasks)); | |
} | |
foreach (var chunk in tasks.Chunk(maxDegreeOfParallelism)) | |
{ | |
await Task.WhenAll(chunk).ConfigureAwait(false); | |
} | |
} | |
/// <summary> | |
/// Executes a callback after task completion and passes in the result from the task | |
/// </summary> | |
/// <typeparam name="T"> </typeparam> | |
/// <param name="task"> The task. </param> | |
/// <param name="tapAsync"> The tap asynchronously. </param> | |
/// <exception cref="ArgumentNullException"> </exception> | |
/// <returns> <![CDATA[Task<T>]]> </returns> | |
public static async Task<T> ThenCallAsync<T>(this Task<T> task, Func<T, Task> tapAsync) | |
{ | |
if (task is null) | |
{ | |
throw new ArgumentNullException(nameof(task)); | |
} | |
if (tapAsync is null) | |
{ | |
throw new ArgumentNullException(nameof(tapAsync)); | |
} | |
var res = await task; | |
await tapAsync(res); | |
return res; | |
} | |
/// <summary> | |
/// Executes a callback after task completion and passes in the result from the task | |
/// </summary> | |
/// <typeparam name="T"> </typeparam> | |
/// <param name="task"> The task. </param> | |
/// <param name="tap"> The tap. </param> | |
/// <exception cref="ArgumentNullException"> </exception> | |
/// <returns> <![CDATA[Task<T>]]> </returns> | |
public static async Task<T> ThenCallAsync<T>(this Task<T> task, Action<T> tap) | |
{ | |
if (task is null) | |
{ | |
throw new ArgumentNullException(nameof(task)); | |
} | |
if (tap is null) | |
{ | |
throw new ArgumentNullException(nameof(tap)); | |
} | |
var res = await task; | |
tap(res); | |
return res; | |
} | |
/// <summary> | |
/// Gets the results. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="tasks">The tasks.</param> | |
/// <param name="tap">The tap.</param> | |
/// <exception cref="ArgumentNullException"></exception> | |
/// <returns><![CDATA[Task<IEnumerable<T>>]]></returns> | |
public static async Task<IEnumerable<T>> GetResultsAsync<T>(this IEnumerable<Task<T>> tasks, Action<T>? tap = null) | |
{ | |
if (tasks is null) | |
{ | |
throw new ArgumentNullException(nameof(tasks)); | |
} | |
var items = new List<T>(); | |
foreach (var t in tasks) | |
{ | |
var result = await t; | |
tap?.Invoke(result); | |
items.Add(result); | |
} | |
return items; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// we use this to group them all as available based on already using this namespace | |
namespace Common.Extensions | |
{ | |
/// <summary> | |
/// adapted from https://archive.ph/2022.10.14-213608/https://betterprogramming.pub/my-top-7-custom-extension-methods-for-net-7-and-c-494acb2e6634#selection-1935.0-2339.1 | |
/// </summary> | |
public static class ValueTaskExtensions | |
{ | |
/// <summary> | |
/// Wraps the executing task in a try/catch | |
/// </summary> | |
/// <param name="task"> The task. </param> | |
/// <param name="errorHandler"> The error handler. </param> | |
/// <param name="rethrow"> If true, rethrow. </param> | |
/// <returns> A ValueTask. </returns> | |
public static async ValueTask TryAsync(this ValueTask task, Action<Exception>? errorHandler = null, bool rethrow = false) | |
{ | |
try | |
{ | |
await task.ConfigureAwait(false); | |
} | |
catch (Exception ex) | |
{ | |
errorHandler?.Invoke(ex); | |
if (rethrow) | |
{ | |
throw; | |
} | |
} | |
} | |
/// <summary> | |
/// Wraps the executing task in a try/catch | |
/// </summary> | |
/// <typeparam name="T"> </typeparam> | |
/// <param name="task"> The task. </param> | |
/// <param name="errorHandler"> The error handler. </param> | |
/// <param name="rethrow"> If true, rethrow. </param> | |
/// <returns> <![CDATA[ValueTask<T>]]> </returns> | |
public static async ValueTask<T?> TryAsync<T>(this ValueTask<T?> task, Action<Exception>? errorHandler = null, bool rethrow = false) where T : class | |
{ | |
try | |
{ | |
return await task.ConfigureAwait(false); | |
} | |
catch (Exception ex) | |
{ | |
errorHandler?.Invoke(ex); | |
if (rethrow) | |
{ | |
throw; | |
} | |
} | |
return default; | |
} | |
/// <summary> | |
/// Returns when all tasks are completed in sequentially asynchronously. | |
/// </summary> | |
/// <typeparam name="T"> </typeparam> | |
/// <param name="tasks"> The tasks. </param> | |
/// <exception cref="ArgumentNullException"> </exception> | |
/// <returns> <![CDATA[ValueTask<IEnumerable<T>>]]> </returns> | |
public static async ValueTask<IEnumerable<T>> WhenAllSequentialAsync<T>(this IEnumerable<ValueTask<T>> tasks) | |
{ | |
if (tasks is null) | |
{ | |
throw new ArgumentNullException(nameof(tasks)); | |
} | |
var results = new List<T>(); | |
foreach (var task in tasks) | |
{ | |
results.Add(await task.ConfigureAwait(false)); | |
} | |
return results; | |
} | |
/// <summary> | |
/// Returns when all tasks are completed in sequentially asynchronously. | |
/// </summary> | |
/// <param name="tasks"> The tasks. </param> | |
/// <exception cref="ArgumentNullException"> </exception> | |
/// <returns> A ValueTask. </returns> | |
public static async ValueTask WhenAllSequentialAsync(this IEnumerable<ValueTask> tasks) | |
{ | |
if (tasks is null) | |
{ | |
throw new ArgumentNullException(nameof(tasks)); | |
} | |
foreach (var task in tasks) | |
{ | |
await task.ConfigureAwait(false); | |
} | |
} | |
/// <summary> | |
/// Executes a callback after task completion and passes in the result from the task | |
/// </summary> | |
/// <typeparam name="T"> </typeparam> | |
/// <param name="task"> The task. </param> | |
/// <param name="tapAsync"> The tap asynchronously. </param> | |
/// <exception cref="ArgumentNullException"> </exception> | |
/// <returns> <![CDATA[ValueTask<T>]]> </returns> | |
public static async ValueTask<T> ThenCallAsync<T>(this ValueTask<T> task, Func<T, ValueTask> tapAsync) | |
{ | |
if (tapAsync is null) | |
{ | |
throw new ArgumentNullException(nameof(tapAsync)); | |
} | |
var res = await task.ConfigureAwait(false); | |
await tapAsync(res).ConfigureAwait(false); | |
return res; | |
} | |
/// <summary> | |
/// Executes a callback after task completion and passes in the result from the task | |
/// </summary> | |
/// <typeparam name="T"> </typeparam> | |
/// <param name="task"> The task. </param> | |
/// <param name="tap"> The tap. </param> | |
/// <exception cref="ArgumentNullException"> </exception> | |
/// <returns> <![CDATA[ValueTask<T>]]> </returns> | |
public static async ValueTask<T> ThenCallAsync<T>(this ValueTask<T> task, Action<T> tap) | |
{ | |
if (tap is null) | |
{ | |
throw new ArgumentNullException(nameof(tap)); | |
} | |
var res = await task.ConfigureAwait(false); | |
tap(res); | |
return res; | |
} | |
/// <summary> | |
/// Gets the results. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="tasks">The tasks.</param> | |
/// <param name="tap">The tap.</param> | |
/// <exception cref="ArgumentNullException"></exception> | |
/// <returns><![CDATA[ValueTask<IEnumerable<T>>]]></returns> | |
public static async ValueTask<IEnumerable<T>> GetResultsAsync<T>(this IEnumerable<ValueTask<T>> tasks, Action<T>? tap = null) | |
{ | |
if (tasks is null) | |
{ | |
throw new ArgumentNullException(nameof(tasks)); | |
} | |
var items = new List<T>(); | |
foreach (var t in tasks) | |
{ | |
var result = await t; | |
tap?.Invoke(result); | |
items.Add(result); | |
} | |
return items; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment