Skip to content

Instantly share code, notes, and snippets.

@ykst
Last active November 24, 2015 05:40
Show Gist options
  • Save ykst/75599365f2c79c9d6450 to your computer and use it in GitHub Desktop.
Save ykst/75599365f2c79c9d6450 to your computer and use it in GitHub Desktop.
Deferred in C#
namespace Deferred
{
public class BasePromise
{
protected enum State
{
Pending,
Fullfilled,
Rejected
}
protected delegate void OnFullfilled();
protected delegate void OnRejected(System.Exception reason);
protected event OnFullfilled onFullfilledHandlers = null;
protected event OnRejected onRejectedHandlers = null;
protected State _state = State.Pending;
protected System.Exception _reason = null;
public bool IsResolved { get { return _state == State.Fullfilled; } }
protected void Defer(OnFullfilled onFullfilled, OnRejected onRejected = null)
{
switch (_state) {
case State.Pending:
onFullfilledHandlers += onFullfilled;
if (onRejected != null) {
onRejectedHandlers += onRejected;
}
break;
case State.Fullfilled:
onFullfilled();
break;
case State.Rejected:
if (onRejected != null) {
onRejected(_reason);
}
break;
}
}
protected void Defer(BasePromise promise, OnFullfilled onFullfilled, System.Action<System.Exception> onRejected = null)
{
Defer(onFullfilled, (reason) => {
ForwardReject(promise, reason, onRejected);
});
}
public void ForwardPromise(Promise promise)
{
Defer(() => {
promise.Resolve();
}, (reason) => {
promise.Reject(reason);
});
}
protected void ForwardReject(BasePromise promise, System.Exception reason, System.Action<System.Exception> onRejected = null)
{
if (onRejected != null) {
try {
onRejected(reason);
}
catch (System.Exception reason2) {
Debug.LogException(reason2);
reason = reason2;
}
}
promise.Reject(reason);
}
public void Reject(System.Exception reason)
{
if (_state != State.Pending) {
throw new System.Exception("illegal promise state");
}
_reason = reason;
if (onRejectedHandlers != null) {
onRejectedHandlers(reason);
}
onRejectedHandlers = null;
_state = State.Rejected;
}
protected void ResolveImpl()
{
if (_state != State.Pending) {
throw new System.Exception("illegal promise state");
}
if (onFullfilledHandlers != null) {
onFullfilledHandlers();
}
onFullfilledHandlers = null;
_state = State.Fullfilled;
}
public BasePromise Unless(System.Action whenNotFullfilled)
{
if (_state == State.Pending) {
whenNotFullfilled();
}
return this;
}
public void Done(System.Action onFullfilled, System.Action<System.Exception> onRejected = null)
{
Defer(() => {
onFullfilled();
}, (reason) => {
if (onRejected != null) {
onRejected(reason);
}
});
}
public void Finally(System.Action onDone)
{
Defer(() => { onDone(); }, (_) => { onDone(); });
}
}
public class Promise : BasePromise
{
public void Resolve()
{
ResolveImpl();
}
public Promise Then(System.Action onFullfilled, System.Action<System.Exception> onRejected = null)
{
Promise promise = new Promise();
Defer(promise, () => {
try {
onFullfilled();
}
catch (System.Exception reason) {
Debug.LogException(reason);
ForwardReject(promise, reason, onRejected);
return;
}
promise.Resolve();
}, onRejected);
return promise;
}
public Promise<T> Then<T>(System.Func<T> onFullfilled, System.Action<System.Exception> onRejected = null)
{
Promise<T> promise = new Promise<T>();
Defer(promise, () => {
T value;
try {
value = onFullfilled();
}
catch (System.Exception reason) {
Debug.LogException(reason);
ForwardReject(promise, reason, onRejected);
return;
}
promise.Resolve(value);
}, onRejected);
return promise;
}
public Promise ThenPromise(System.Func<Promise> onFullfilled, System.Action<System.Exception> onRejected = null)
{
Promise promise = new Promise();
Defer(promise, () => {
Promise nextPromise;
try {
nextPromise = onFullfilled();
}
catch (System.Exception reason) {
Debug.LogException(reason);
ForwardReject(promise, reason, onRejected);
return;
}
nextPromise.ForwardPromise(promise);
}, onRejected);
return promise;
}
public Promise Catch(System.Action<System.Exception> onRejected)
{
Promise promise = new Promise();
Defer(promise, promise.Resolve, onRejected);
return promise;
}
public static Promise Always()
{
Promise promise = new Promise();
promise.Resolve();
return promise;
}
}
public class Promise<T> : BasePromise
{
T _value;
public void Resolve(T value)
{
_value = value;
ResolveImpl();
}
public Promise Then(System.Action<T> onFullfilled, System.Action<System.Exception> onRejected = null)
{
Promise promise = new Promise();
Defer(promise, () => {
try {
onFullfilled(_value);
}
catch (System.Exception reason) {
Debug.LogException(reason);
ForwardReject(promise, reason, onRejected);
return;
}
promise.Resolve();
}, onRejected);
return promise;
}
public Promise<R> Then<R>(System.Func<T, R> onFullfilled, System.Action<System.Exception> onRejected = null)
{
Promise<R> promise = new Promise<R>();
Defer(promise, () => {
R nextValue;
try {
nextValue = onFullfilled(_value);
}
catch (System.Exception reason) {
Debug.LogException(reason);
ForwardReject(promise, reason, onRejected);
return;
}
promise.Resolve(nextValue);
}, onRejected);
return promise;
}
public Promise ThenPromise(System.Func<T, Promise> onFullfilled, System.Action<System.Exception> onRejected = null)
{
Promise promise = new Promise();
Defer(promise, () => {
Promise nextPromise;
try {
nextPromise = onFullfilled(_value);
}
catch (System.Exception reason) {
Debug.LogException(reason);
ForwardReject(promise, reason, onRejected);
return;
}
nextPromise.ForwardPromise(promise);
}, onRejected);
return promise;
}
public void Done(System.Action<T> onFullfilled, System.Action<System.Exception> onRejected = null)
{
Defer(() => {
onFullfilled(_value);
}, (reason) => {
if (onRejected != null) {
onRejected(reason);
}
});
}
public Promise<T> Catch(System.Action<System.Exception> onRejected)
{
Promise<T> promise = new Promise<T>();
Defer(promise, () => {
promise.Resolve(_value);
}, onRejected);
return promise;
}
public static Promise<T> Always(T value)
{
Promise<T> promise = new Promise<T>();
promise.Resolve(value);
return promise;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment