// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Runtime.CompilerServices; namespace System.Threading.Tasks { internal static class ForceAsyncTaskExtensions { /// /// Returns an awaitable/awaiter that will ensure the continuation is executed /// asynchronously on the thread pool, even if the task is already completed /// by the time the await occurs. Effectively, it is equivalent to awaiting /// with ConfigureAwait(false) and then queuing the continuation with Task.Run, /// but it avoids the extra hop if the continuation already executed asynchronously. /// public static ForceAsyncAwaiter ForceAsync(this Task task) { return new ForceAsyncAwaiter(task); } public static ForceAsyncAwaiter ForceAsync(this Task task) { return new ForceAsyncAwaiter(task); } } internal readonly struct ForceAsyncAwaiter : ICriticalNotifyCompletion { private readonly Task _task; internal ForceAsyncAwaiter(Task task) { _task = task; } public ForceAsyncAwaiter GetAwaiter() { return this; } // The purpose of this type is to always force a continuation public bool IsCompleted => false; public void GetResult() { _task.GetAwaiter().GetResult(); } public void OnCompleted(Action action) { _task.ConfigureAwait(false).GetAwaiter().OnCompleted(action); } public void UnsafeOnCompleted(Action action) { _task.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted(action); } } internal readonly struct ForceAsyncAwaiter : ICriticalNotifyCompletion { private readonly Task _task; internal ForceAsyncAwaiter(Task task) { _task = task; } public ForceAsyncAwaiter GetAwaiter() { return this; } // The purpose of this type is to always force a continuation public bool IsCompleted => false; public T GetResult() { return _task.GetAwaiter().GetResult(); } public void OnCompleted(Action action) { _task.ConfigureAwait(false).GetAwaiter().OnCompleted(action); } public void UnsafeOnCompleted(Action action) { _task.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted(action); } } }