DotNext by Roman Sakno

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

 Future

public abstract class Future : IFuture, INotifyCompletion
Represents lightweight version of Task.
using System; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; namespace DotNext.Threading.Tasks { public abstract class Future : IFuture, INotifyCompletion { public interface IAwaiter : IFuture, INotifyCompletion { void GetResult(); } public interface IAwaiter<[System.Runtime.CompilerServices.Nullable(2)] out TResult> : IFuture, INotifyCompletion { [System.Runtime.CompilerServices.NullableContext(1)] TResult GetResult(); } protected sealed class IncompletedFutureException : InvalidOperationException { } [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] private sealed class Continuation { private readonly Action callback; private readonly object context; private Continuation(Action callback, SynchronizationContext context) { this.callback = callback; this.context = context; } private Continuation(Action callback, TaskScheduler scheduler) { this.callback = callback; context = scheduler; } private void Invoke() { object obj = context; SynchronizationContext synchronizationContext = obj as SynchronizationContext; if (synchronizationContext == null) { TaskScheduler taskScheduler = obj as TaskScheduler; if (taskScheduler != null) Task.Factory.StartNew(callback, CancellationToken.None, TaskCreationOptions.DenyChildAttach, taskScheduler); else callback(); } else callback.InvokeInContext(synchronizationContext); } internal static Action Create(Action callback) { SynchronizationContext synchronizationContext = SynchronizationContext.Current?.CreateCopy(); if (synchronizationContext != null) return new Continuation(callback, synchronizationContext).Invoke; TaskScheduler current = TaskScheduler.Current; if (current == TaskScheduler.Default) return callback.InvokeInThreadPool; return new Continuation(callback, current).Invoke; } } private readonly bool runContinuationsAsynchronously; [System.Runtime.CompilerServices.Nullable(2)] private Action continuation; public abstract bool IsCompleted { get; } protected Future(bool runContinuationsAsynchronously = true) { this.runContinuationsAsynchronously = runContinuationsAsynchronously; } [MethodImpl(MethodImplOptions.Synchronized)] protected void Complete() { Interlocked.Exchange(ref continuation, null)?.Invoke(); } [MethodImpl(MethodImplOptions.Synchronized)] [System.Runtime.CompilerServices.NullableContext(1)] public void OnCompleted(Action callback) { if (IsCompleted) callback(); else continuation = (Action)Delegate.Combine(continuation, runContinuationsAsynchronously ? Continuation.Create(callback) : callback); } } }