<PackageReference Include="Microsoft.Bcl.TimeProvider" Version="10.0.1" />

TimeProviderTaskExtensions

public static class TimeProviderTaskExtensions
Provides extensions methods for Task operations with TimeProvider.
using System.Runtime.CompilerServices; namespace System.Threading.Tasks { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] public static class TimeProviderTaskExtensions { private sealed class DelayState : TaskCompletionSource<bool> { public ITimer Timer { get; set; } public CancellationToken CancellationToken { get; } public CancellationTokenRegistration Registration { get; set; } public DelayState(CancellationToken cancellationToken) { CancellationToken = cancellationToken; } } private sealed class WaitAsyncState : TaskCompletionSource<bool> { public readonly CancellationTokenSource ContinuationCancellation = new CancellationTokenSource(); public CancellationTokenRegistration Registration; public ITimer Timer; public CancellationToken CancellationToken { get; } public WaitAsyncState(CancellationToken cancellationToken) : base(TaskCreationOptions.RunContinuationsAsynchronously) { CancellationToken = cancellationToken; } } public static Task Delay(this TimeProvider timeProvider, TimeSpan delay, CancellationToken cancellationToken = default(CancellationToken)) { if (timeProvider == TimeProvider.System) return Task.Delay(delay, cancellationToken); ExceptionPolyfills.ThrowIfNull(timeProvider, "timeProvider"); if (delay != Timeout.InfiniteTimeSpan && delay < TimeSpan.Zero) throw new ArgumentOutOfRangeException("delay"); if (cancellationToken.IsCancellationRequested) return Task.FromCanceled(cancellationToken); if (delay == TimeSpan.Zero) return Task.CompletedTask; DelayState delayState2 = new DelayState(cancellationToken); delayState2.Timer = timeProvider.CreateTimer(delegate(object delayState) { DelayState obj2 = (DelayState)delayState; obj2.TrySetResult(true); obj2.Registration.Dispose(); obj2.Timer?.Dispose(); }, delayState2, delay, Timeout.InfiniteTimeSpan); delayState2.Registration = cancellationToken.Register(delegate(object delayState) { DelayState delayState3 = (DelayState)delayState; ThreadPool.UnsafeQueueUserWorkItem(delegate(object state) { DelayState obj = (DelayState)state; obj.TrySetCanceled(obj.CancellationToken); }, delayState3); delayState3.Registration.Dispose(); delayState3.Timer?.Dispose(); }, delayState2); if (delayState2.Task.IsCompleted) { delayState2.Registration.Dispose(); delayState2.Timer.Dispose(); } return delayState2.Task; } public static Task WaitAsync(this Task task, TimeSpan timeout, TimeProvider timeProvider, CancellationToken cancellationToken = default(CancellationToken)) { ExceptionPolyfills.ThrowIfNull(task, "task"); if (timeout != Timeout.InfiniteTimeSpan && timeout < TimeSpan.Zero) throw new ArgumentOutOfRangeException("timeout"); ExceptionPolyfills.ThrowIfNull(timeProvider, "timeProvider"); if (task.IsCompleted) return task; if (timeout == Timeout.InfiniteTimeSpan && !cancellationToken.CanBeCanceled) return task; if (cancellationToken.IsCancellationRequested) return Task.FromCanceled(cancellationToken); if (timeout == TimeSpan.Zero) return Task.FromException(new TimeoutException()); WaitAsyncState waitAsyncState = new WaitAsyncState(cancellationToken); waitAsyncState.Timer = timeProvider.CreateTimer(delegate(object s) { WaitAsyncState obj2 = (WaitAsyncState)s; obj2.TrySetException(new TimeoutException()); obj2.Registration.Dispose(); obj2.Timer?.Dispose(); obj2.ContinuationCancellation.Cancel(); }, waitAsyncState, timeout, Timeout.InfiniteTimeSpan); task.ContinueWith(delegate(Task t, object s) { WaitAsyncState waitAsyncState2 = (WaitAsyncState)s; if (t.IsFaulted) waitAsyncState2.TrySetException(t.Exception.InnerExceptions); else if (t.IsCanceled) { waitAsyncState2.TrySetCanceled(); } else { waitAsyncState2.TrySetResult(true); } waitAsyncState2.Registration.Dispose(); waitAsyncState2.Timer?.Dispose(); }, waitAsyncState, waitAsyncState.ContinuationCancellation.Token, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); waitAsyncState.Registration = cancellationToken.Register(delegate(object s) { WaitAsyncState obj = (WaitAsyncState)s; obj.TrySetCanceled(obj.CancellationToken); obj.Timer?.Dispose(); obj.ContinuationCancellation.Cancel(); }, waitAsyncState); if (waitAsyncState.Task.IsCompleted) { waitAsyncState.Registration.Dispose(); waitAsyncState.Timer.Dispose(); } return waitAsyncState.Task; } [AsyncStateMachine(typeof(<WaitAsync>d__4<>))] public static Task<TResult> WaitAsync<[System.Runtime.CompilerServices.Nullable(2)] TResult>(this Task<TResult> task, TimeSpan timeout, TimeProvider timeProvider, CancellationToken cancellationToken = default(CancellationToken)) { <WaitAsync>d__4<TResult> stateMachine = default(<WaitAsync>d__4<TResult>); stateMachine.<>t__builder = AsyncTaskMethodBuilder<TResult>.Create(); stateMachine.task = task; stateMachine.timeout = timeout; stateMachine.timeProvider = timeProvider; stateMachine.cancellationToken = cancellationToken; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } public static CancellationTokenSource CreateCancellationTokenSource(this TimeProvider timeProvider, TimeSpan delay) { ExceptionPolyfills.ThrowIfNull(timeProvider, "timeProvider"); if (delay != Timeout.InfiniteTimeSpan && delay < TimeSpan.Zero) throw new ArgumentOutOfRangeException("delay"); if (timeProvider == TimeProvider.System) return new CancellationTokenSource(delay); CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); ITimer state = timeProvider.CreateTimer(delegate(object s) { try { ((CancellationTokenSource)s).Cancel(); } catch (ObjectDisposedException) { } }, cancellationTokenSource, delay, Timeout.InfiniteTimeSpan); cancellationTokenSource.Token.Register(delegate(object t) { ((ITimer)t).Dispose(); }, state); return cancellationTokenSource; } } }