Skip to content

Instantly share code, notes, and snippets.

@mckabue
Forked from dbones/Promise.cs
Created August 21, 2020 07:31
Show Gist options
  • Save mckabue/60863f5f84a30bb2879445f8fbd804fd to your computer and use it in GitHub Desktop.
Save mckabue/60863f5f84a30bb2879445f8fbd804fd to your computer and use it in GitHub Desktop.
C# Promises (again because i can), note this is not A+ standard, but functions similar to it
namespace Promise.CommandLine
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Action step2 = () => Console.WriteLine(454545);
Action<int> stepb = i => Console.WriteLine(++i);
var p = Promise.When(()=> 1);
p.Then(step2)
//.Then(() => { throw new Exception(); })
.Then(() => Console.WriteLine("hi"))
.Catch(e => Console.WriteLine("ERROR"))
.Finally(()=> Console.WriteLine("must run this code"));
p.Then(stepb).Finally(()=> Console.WriteLine("end"));
Console.ReadKey();
}
}
public interface IThenable<out T> : IThenable
{
IThenable Then(Action<T> action);
IThenable<TOut> Then<TOut>(Func<T, TOut> func);
}
public interface IThenable : IFinally
{
IThenable Then(IThenable thenable);
IThenable Then(Task task);
IThenable Then(Action action);
IThenable<TOut> Then<TOut>(Task<TOut> task);
IThenable<TOut> Then<TOut>(Func<TOut> func);
IFinally Catch(Action<Exception> handle);
void Invoke();
void Throw(Exception exception);
}
public interface IFinally
{
void Finally(Action action);
}
public abstract partial class Promise
{
public static Deferred Defer()
{
return new Deferred();
}
public static Deferred<T> Defer<T>()
{
return new Deferred<T>();
}
public static IThenable When(Action action)
{
return TaskPromise.When(action);
}
public static IThenable When(Task task)
{
return TaskPromise.When(task);
}
public static IThenable When(Call action)
{
return ResolvePromise.When(action);
}
public static IThenable<T> When<T>(Call<T> action)
{
return ResolvePromise<T>.When(action);
}
public static IThenable<T> When<T>(Task<T> task)
{
return TaskPromise<T>.When(task);
}
public static IThenable<T> When<T>(Func<T> func)
{
return TaskPromise<T>.When(func);
}
public static IThenable<object[]> All(params TaskPromise[] taskPromises)
{
var deferred = Defer<object[]>();
var results = new object[taskPromises.Length];
var errors = new Exception[taskPromises.Length];
var completed = 0;
Action call = () =>
{
completed++;
if (completed != taskPromises.Length) return;
if(errors.Any(entry => entry != null)) deferred.Reject(new PromiseAllException(errors));
else deferred.Resolve(results);
};
for (int i = 0; i < taskPromises.Length; i++)
{
var p = taskPromises[i];
var index = i;
p.Then(() =>
{
results[index] = p.GetResult();
call();
})
.Catch(ex =>
{
errors[index] = ex;
call();
});
}
return deferred.Thenable;
}
}
public class PromiseAllException : Exception
{
public Exception[] Exceptions { get; private set; }
public PromiseAllException(Exception[] exceptions)
{
Exceptions = exceptions;
}
}
public class TaskPromise : Promise
{
public Task Task { get; set; }
protected TaskPromise() { }
internal protected override void Handle()
{
if (Task.IsFaulted || Task.IsCanceled)
{
Exception = Task.Exception;
Task.Dispose();
Task = null;
Throw(Exception);
return;
}
base.Handle();
Task.Dispose();
Task = null;
}
internal protected static TaskPromise CreateOnly(Task task)
{
var promise = new TaskPromise { Task = task };
promise.Task.GetAwaiter().OnCompleted(promise.Handle);
return promise;
}
public static TaskPromise When(Action action)
{
var promise = CreateOnly(new Task(action));
promise.Invoke();
return promise;
}
public static TaskPromise When(Task task)
{
var promise = CreateOnly(task);
promise.Invoke();
return promise;
}
public override void Invoke()
{
if (_executed)
{
Handle();
return;
}
_executed = true;
Task.Start();
}
}
public class TaskPromise<T> : TaskPromise, IThenable<T>
{
public T Result { get; set; }
protected TaskPromise() { }
protected internal override void Handle()
{
Result = ((Task<T>)Task).Result;
base.Handle();
}
internal protected static TaskPromise<T> CreateOnly(Task<T> task)
{
var promise = new TaskPromise<T> { Task = task };
promise.Task.GetAwaiter().OnCompleted(promise.Handle);
return promise;
}
public static TaskPromise<T> When(Task<T> task)
{
var promise = CreateOnly(task);
promise.Invoke();
return promise;
}
public static TaskPromise<T> When(Func<T> func)
{
var promise = CreateOnly(new Task<T>(func));
promise.Invoke();
return promise;
}
public IThenable Then(Action<T> action)
{
Action invoke = () => action(Result);
var promise = CreateOnly(new Task(invoke));
EnsureThenableIsChained(promise);
return promise;
}
public IThenable<TOut> Then<TOut>(Func<T, TOut> func)
{
Func<TOut> invoke = () => func(Result);
var promise = TaskPromise<TOut>.CreateOnly(new Task<TOut>(invoke));
EnsureThenableIsChained(promise);
return promise;
}
protected internal override object GetResult()
{
return Result;
}
}
public delegate void Call(Action resolve, Action<Exception> reject);
public delegate void Call<out T>(Action<T> resolve, Action<Exception> reject);
public class ResolvePromise : Promise
{
public Action Action { get; set; }
protected ResolvePromise() { }
public void Resolve()
{
Handle();
}
public void Reject(Exception ex)
{
Throw(ex);
}
public static ResolvePromise When(Call action)
{
var promise = CreateOnly(action);
promise.Invoke();
return promise;
}
internal protected static ResolvePromise CreateOnly(Call action)
{
var promise = new ResolvePromise();
promise.Action = () => { action(promise.Resolve, promise.Reject); };
return promise;
}
public override void Invoke()
{
if (_executed)
{
Handle();
return;
}
_executed = true;
Action();
}
}
public class ResolvePromise<T> : ResolvePromise, IThenable<T>
{
public T Result { get; set; }
protected ResolvePromise() { }
public void Resolve(T result)
{
Result = result;
Handle();
}
public static ResolvePromise<T> When(Call<T> action)
{
var promise = CreateOnly(action);
promise.Invoke();
return promise;
}
protected internal override object GetResult()
{
return Result;
}
internal protected static ResolvePromise<T> CreateOnly(Call<T> action)
{
var promise = new ResolvePromise<T>();
promise.Action = () => { action(promise.Resolve, promise.Reject); };
return promise;
}
public IThenable Then(Action<T> action)
{
Action invoke = () => action(Result);
var promise = TaskPromise.CreateOnly(new Task(invoke));
EnsureThenableIsChained(promise);
return promise;
}
public IThenable<TOut> Then<TOut>(Func<T, TOut> func)
{
Func<TOut> invoke = () => func(Result);
var promise = TaskPromise<TOut>.CreateOnly(new Task<TOut>(invoke));
EnsureThenableIsChained(promise);
return promise;
}
}
public class Deferred
{
public IThenable Thenable { get; private set; }
private Action _resolve;
private Action<Exception> _reject;
public Deferred()
{
Thenable = Promise.When((resolve, reject) =>
{
_resolve = resolve;
_reject = reject;
});
}
public void Resolve()
{
_resolve();
}
public void Reject(Exception exception)
{
_reject(exception);
}
}
public class Deferred<T>
{
public IThenable<T> Thenable { get; private set; }
private Action<T> _resolve;
private Action<Exception> _reject;
public Deferred()
{
Thenable = Promise.When<T>((resolve, reject) =>
{
_resolve = resolve;
_reject = reject;
});
}
public void Resolve(T result)
{
_resolve(result);
}
public void Reject(Exception exception)
{
_reject(exception);
}
}
public abstract partial class Promise : IThenable
{
protected bool _executed = false;
protected readonly LinkedList<IThenable> _thenables;
protected readonly LinkedList<Action<Exception>> _exceptionHandlers;
protected readonly LinkedList<Action> _finallyHandlers;
public Exception Exception { get; set; }
protected Promise()
{
_thenables = new LinkedList<IThenable>();
_exceptionHandlers = new LinkedList<Action<Exception>>();
_finallyHandlers = new LinkedList<Action>();
}
public IThenable Then(IThenable thenable)
{
EnsureThenableIsChained(thenable);
return thenable;
}
public virtual IThenable Then(Task task)
{
var promise = TaskPromise.CreateOnly(task);
EnsureThenableIsChained(promise);
return promise;
}
public virtual IThenable Then(Action action)
{
var promise = TaskPromise.CreateOnly(new Task(action));
EnsureThenableIsChained(promise);
return promise;
}
public virtual IThenable<TOut> Then<TOut>(Task<TOut> task)
{
var promise = TaskPromise<TOut>.CreateOnly(task);
EnsureThenableIsChained(promise);
return promise;
}
public virtual IThenable<TOut> Then<TOut>(Func<TOut> func)
{
var promise = TaskPromise<TOut>.CreateOnly(new Task<TOut>(func));
EnsureThenableIsChained(promise);
return promise;
}
public abstract void Invoke();
internal protected virtual void Handle()
{
if (Exception != null && _exceptionHandlers.Any())
{
foreach (var exceptionHandler in _exceptionHandlers)
{
exceptionHandler(Exception);
}
foreach (var thenable in _thenables)
{
thenable.Throw(Exception);
}
_thenables.Clear();
_exceptionHandlers.Clear();
}
if (Exception == null && _thenables.Any())
{
foreach (var thenable in _thenables)
{
thenable.Invoke();
}
_thenables.Clear();
}
if (_finallyHandlers.Any())
{
foreach (var finallyHandler in _finallyHandlers)
{
finallyHandler();
}
_finallyHandlers.Clear();
}
}
public virtual void Throw(Exception exception)
{
Exception = exception;
Handle();
}
public virtual IFinally Catch(Action<Exception> handle)
{
_exceptionHandlers.AddLast(handle);
return this;
}
protected virtual void EnsureThenableIsChained(IThenable thenable)
{
if (_executed)
{
if (Exception == null)
{
thenable.Invoke();
}
else
{
thenable.Throw(Exception);
}
return;
}
_thenables.AddLast(thenable);
}
public void Finally(Action action)
{
_finallyHandlers.AddLast(action);
}
internal protected virtual object GetResult()
{
return null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment