You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Zero/ZeroLevel/Services/Async/TaskExtensions.cs

156 lines
7.1 KiB

using System;
using System.Threading;
using System.Threading.Tasks;
namespace ZeroLevel.Services.Async
{
/// <summary>
/// Provides synchronous extension methods for tasks.
/// </summary>
public static class TaskExtensions
{
/// <summary>
/// Asynchronously waits for the task to complete, or for the cancellation token to be canceled.
/// </summary>
/// <param name="this">The task to wait for. May not be <c>null</c>.</param>
/// <param name="cancellationToken">The cancellation token that cancels the wait.</param>
public static Task WaitAsync(this Task @this, CancellationToken cancellationToken)
{
if (@this == null)
throw new ArgumentNullException(nameof(@this));
if (!cancellationToken.CanBeCanceled)
return @this;
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled(cancellationToken);
return DoWaitAsync(@this, cancellationToken);
}
private static async Task DoWaitAsync(Task task, CancellationToken cancellationToken)
{
using (var cancelTaskSource = new CancellationTokenTaskSource<object>(cancellationToken))
await await Task.WhenAny(task, cancelTaskSource.Task).ConfigureAwait(false);
}
/// <summary>
/// Asynchronously waits for the task to complete, or for the cancellation token to be canceled.
/// </summary>
/// <typeparam name="TResult">The type of the task result.</typeparam>
/// <param name="this">The task to wait for. May not be <c>null</c>.</param>
/// <param name="cancellationToken">The cancellation token that cancels the wait.</param>
public static Task<TResult> WaitAsync<TResult>(this Task<TResult> @this, CancellationToken cancellationToken)
{
if (@this == null)
throw new ArgumentNullException(nameof(@this));
if (!cancellationToken.CanBeCanceled)
return @this;
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled<TResult>(cancellationToken);
return DoWaitAsync(@this, cancellationToken);
}
private static async Task<TResult> DoWaitAsync<TResult>(Task<TResult> task, CancellationToken cancellationToken)
{
using (var cancelTaskSource = new CancellationTokenTaskSource<TResult>(cancellationToken))
return await await Task.WhenAny(task, cancelTaskSource.Task).ConfigureAwait(false);
}
/// <summary>
/// Waits for the task to complete, unwrapping any exceptions.
/// </summary>
/// <param name="task">The task. May not be <c>null</c>.</param>
public static void WaitAndUnwrapException(this Task task)
{
task.GetAwaiter().GetResult();
}
/// <summary>
/// Waits for the task to complete, unwrapping any exceptions.
/// </summary>
/// <param name="task">The task. May not be <c>null</c>.</param>
/// <param name="cancellationToken">A cancellation token to observe while waiting for the task to complete.</param>
/// <exception cref="OperationCanceledException">The <paramref name="cancellationToken"/> was cancelled before the <paramref name="task"/> completed, or the <paramref name="task"/> raised an <see cref="OperationCanceledException"/>.</exception>
public static void WaitAndUnwrapException(this Task task, CancellationToken cancellationToken)
{
try
{
task.Wait(cancellationToken);
}
catch (AggregateException ex)
{
throw ExceptionHelpers.PrepareForRethrow(ex.InnerException);
}
}
/// <summary>
/// Waits for the task to complete, unwrapping any exceptions.
/// </summary>
/// <typeparam name="TResult">The type of the result of the task.</typeparam>
/// <param name="task">The task. May not be <c>null</c>.</param>
/// <returns>The result of the task.</returns>
public static TResult WaitAndUnwrapException<TResult>(this Task<TResult> task)
{
return task.GetAwaiter().GetResult();
}
/// <summary>
/// Waits for the task to complete, unwrapping any exceptions.
/// </summary>
/// <typeparam name="TResult">The type of the result of the task.</typeparam>
/// <param name="task">The task. May not be <c>null</c>.</param>
/// <param name="cancellationToken">A cancellation token to observe while waiting for the task to complete.</param>
/// <returns>The result of the task.</returns>
/// <exception cref="OperationCanceledException">The <paramref name="cancellationToken"/> was cancelled before the <paramref name="task"/> completed, or the <paramref name="task"/> raised an <see cref="OperationCanceledException"/>.</exception>
public static TResult WaitAndUnwrapException<TResult>(this Task<TResult> task, CancellationToken cancellationToken)
{
try
{
task.Wait(cancellationToken);
return task.Result;
}
catch (AggregateException ex)
{
throw ExceptionHelpers.PrepareForRethrow(ex.InnerException);
}
}
/// <summary>
/// Waits for the task to complete, but does not raise task exceptions. The task exception (if any) is unobserved.
/// </summary>
/// <param name="task">The task. May not be <c>null</c>.</param>
public static void WaitWithoutException(this Task task)
{
// Check to see if it's completed first, so we don't cause unnecessary allocation of a WaitHandle.
if (task.IsCompleted)
{
return;
}
var asyncResult = (IAsyncResult)task;
asyncResult.AsyncWaitHandle.WaitOne();
}
/// <summary>
/// Waits for the task to complete, but does not raise task exceptions. The task exception (if any) is unobserved.
/// </summary>
/// <param name="task">The task. May not be <c>null</c>.</param>
/// <param name="cancellationToken">A cancellation token to observe while waiting for the task to complete.</param>
/// <exception cref="OperationCanceledException">The <paramref name="cancellationToken"/> was cancelled before the <paramref name="task"/> completed.</exception>
public static void WaitWithoutException(this Task task, CancellationToken cancellationToken)
{
// Check to see if it's completed first, so we don't cause unnecessary allocation of a WaitHandle.
if (task.IsCompleted)
{
return;
}
cancellationToken.ThrowIfCancellationRequested();
var index = WaitHandle.WaitAny(new[] { ((IAsyncResult)task).AsyncWaitHandle, cancellationToken.WaitHandle });
if (index != 0)
{
cancellationToken.ThrowIfCancellationRequested();
}
}
}
}

Powered by TurnKey Linux.