DotNext by .NET Foundation and Contributors

<PackageReference Include="DotNext" Version="4.12.4" />

 DynamicTaskAwaitable

public struct DynamicTaskAwaitable
Represents dynamically-typed task.
using DotNext.Dynamic; using DotNext.Reflection; using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading.Tasks; namespace DotNext.Threading.Tasks { [StructLayout(LayoutKind.Auto)] public readonly struct DynamicTaskAwaitable { [StructLayout(LayoutKind.Auto)] public readonly struct Awaiter : ICriticalNotifyCompletion, INotifyCompletion { private readonly Task task; private readonly ConfiguredTaskAwaitable.ConfiguredTaskAwaiter awaiter; public bool IsCompleted => awaiter.IsCompleted; internal Awaiter(Task task, bool continueOnCaptureContext) { this.task = task; awaiter = task.ConfigureAwait(continueOnCaptureContext).GetAwaiter(); } [System.Runtime.CompilerServices.NullableContext(1)] public void OnCompleted(Action continuation) { awaiter.OnCompleted(continuation); } void ICriticalNotifyCompletion.UnsafeOnCompleted(Action continuation) { awaiter.UnsafeOnCompleted(continuation); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsTaskWithResult(Type type) { if (type != TaskType.CompletedTaskType) return type.IsConstructedGenericType; return false; } internal object GetRawResult() { if (!IsTaskWithResult(task.GetType())) return Missing.Value; return GetResultCallSite.Target(GetResultCallSite, task); } [System.Runtime.CompilerServices.NullableContext(2)] [RequiresUnreferencedCode("Runtime binding may be incompatible with IL trimming")] public dynamic GetResult() { if (IsTaskWithResult(task.GetType())) return GetResultCallSite.Target(GetResultCallSite, task); awaiter.GetResult(); return Missing.Value; } } private static readonly CallSite<Func<CallSite, Task, object>> GetResultCallSite = CallSite<Func<CallSite, Task, object>>.Create(new TaskResultBinder()); private readonly Task task; private readonly bool continueOnCapturedContext; internal DynamicTaskAwaitable(Task task, bool continueOnCapturedContext = true) { this.task = task; this.continueOnCapturedContext = continueOnCapturedContext; } public DynamicTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) { return new DynamicTaskAwaitable(task, continueOnCapturedContext); } public Awaiter GetAwaiter() { return new Awaiter(task, continueOnCapturedContext); } } }