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);
}
}
}