Skip to content

Instantly share code, notes, and snippets.

@doeringp
Created March 29, 2023 10:37
Show Gist options
  • Save doeringp/a416768ab19ac8a8877569a7ba61db5f to your computer and use it in GitHub Desktop.
Save doeringp/a416768ab19ac8a8877569a7ba61db5f to your computer and use it in GitHub Desktop.
Extends Task.WhenAny to return only a task if a condition matches
public static class AsyncExtensions
{
/// <summary>
/// Creates a task that will complete when any of the tasks have completed and the task result matches the <paramref name="condition"/>.
/// </summary>
/// <typeparam name="TResult">The result type produced by each task in the list.</typeparam>
/// <param name="tasks">The tasks to wait on for completion.</param>
/// <param name="condition">The condition the completed task should match in order to be returned.</param>
/// <returns>
/// A task that represents the completion of one of the supplied tasks.
/// The return Task's Result is the result of the first task that completed and matched the <paramref name="condition"/>.
/// </returns>
/// <exception cref="System.ArgumentNullException">
/// The <paramref name="tasks"/> or <paramref name="condition"/> argument was null.
/// </exception>
/// <exception cref="System.ArgumentException">
/// The <paramref name="tasks"/> collection contained a null task, or was empty.
/// </exception>
public static async Task<TResult?> WhenAny<TResult>(this ICollection<Task<TResult>> tasks, Predicate<TResult> condition)
{
ArgumentNullException.ThrowIfNull(tasks);
ArgumentNullException.ThrowIfNull(condition);
if (!tasks.Any())
{
throw new ArgumentException("The tasks list was empty.", nameof(tasks));
}
while (tasks.Count > 0)
{
var task = await Task.WhenAny(tasks);
TResult result = await task;
if (condition(result))
{
return result;
}
tasks.Remove(task);
}
return default;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment