Created
May 13, 2014 15:38
-
-
Save hyakugei/78567e943389e3f83c64 to your computer and use it in GitHub Desktop.
TaskHelper rewritten for Unity/Parse use.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright (c) 2012 Rizal Almashoor | |
// Licensed under the MIT license. | |
// http://gist.github.com/2818038#file_license.txt | |
// | |
// Additions as suggested by Mike Cann - http://www.mikecann.co.uk/personal-project/fixing-unitys-internal-compiler-error/ | |
// | |
// | |
using System.Linq; | |
namespace System.Threading.Tasks | |
{ | |
public static class TaskHelper | |
{ | |
// Inspired by http://blogs.msdn.com/b/pfxteam/archive/2010/11/21/10094564.aspx | |
public static Task Then(this Task task, Action<Task> next) | |
{ | |
if (task == null) throw new ArgumentNullException("task"); | |
if (next == null) throw new ArgumentNullException("next"); | |
var tcs = new TaskCompletionSource<AsyncVoid>(); | |
task.ContinueWith(previousTask => { | |
if (previousTask.IsFaulted) tcs.TrySetException(previousTask.Exception); | |
else if (previousTask.IsCanceled) tcs.TrySetCanceled(); | |
else | |
{ | |
try | |
{ | |
next(previousTask); | |
tcs.TrySetResult(default(AsyncVoid)); | |
} | |
catch (Exception ex) | |
{ | |
tcs.TrySetException(ex); | |
} | |
} | |
}); | |
return tcs.Task; | |
} | |
public static Task Then(this Task task, Func<Task, Task> next) | |
{ | |
if (task == null) throw new ArgumentNullException("task"); | |
if (next == null) throw new ArgumentNullException("next"); | |
var tcs = new TaskCompletionSource<AsyncVoid>(); | |
task.ContinueWith(previousTask => { | |
if (previousTask.IsFaulted) tcs.TrySetException(previousTask.Exception); | |
else if (previousTask.IsCanceled) tcs.TrySetCanceled(); | |
else | |
{ | |
try | |
{ | |
next(previousTask).ContinueWith(nextTask => | |
{ | |
if (nextTask.IsFaulted) tcs.TrySetException(nextTask.Exception); | |
else if (nextTask.IsCanceled) tcs.TrySetCanceled(); | |
else tcs.TrySetResult(default(AsyncVoid)); | |
}); | |
} | |
catch (Exception ex) | |
{ | |
tcs.TrySetException(ex); | |
} | |
} | |
}); | |
return tcs.Task; | |
} | |
public static Task<TNextResult> Then<TNextResult>(this Task task, Func<Task, TNextResult> next) | |
{ | |
if (task == null) throw new ArgumentNullException("task"); | |
if (next == null) throw new ArgumentNullException("next"); | |
var tcs = new TaskCompletionSource<TNextResult>(); | |
task.ContinueWith(previousTask => { | |
if (previousTask.IsFaulted) tcs.TrySetException(previousTask.Exception); | |
else if (previousTask.IsCanceled) tcs.TrySetCanceled(); | |
else | |
{ | |
try | |
{ | |
tcs.TrySetResult(next(previousTask)); | |
} | |
catch (Exception ex) | |
{ | |
tcs.TrySetException(ex); | |
} | |
} | |
}); | |
return tcs.Task; | |
} | |
public static Task<TNextResult> Then<TNextResult>(this Task task, Func<Task, Task<TNextResult>> next) | |
{ | |
if (task == null) throw new ArgumentNullException("task"); | |
if (next == null) throw new ArgumentNullException("next"); | |
var tcs = new TaskCompletionSource<TNextResult>(); | |
Action<Task> a = previousTask => | |
{ | |
if (previousTask.IsFaulted) tcs.TrySetException(previousTask.Exception); | |
else if (previousTask.IsCanceled) tcs.TrySetCanceled(); | |
else | |
{ | |
try | |
{ | |
Action<Task<TNextResult>> b = nextTask => | |
{ | |
if (nextTask.IsFaulted) tcs.TrySetException(nextTask.Exception); | |
else if (nextTask.IsCanceled) tcs.TrySetCanceled(); | |
else | |
{ | |
try | |
{ | |
tcs.TrySetResult(nextTask.Result); | |
} | |
catch (Exception ex) | |
{ | |
tcs.TrySetException(ex); | |
} | |
} | |
}; | |
next(previousTask).ContinueWith(b); | |
} | |
catch (Exception ex) | |
{ | |
tcs.TrySetException(ex); | |
} | |
} | |
}; | |
task.ContinueWith(a); | |
return tcs.Task; | |
} | |
public static Task Then<TResult>(this Task<TResult> task, Action<Task<TResult>> next) | |
{ | |
if (task == null) throw new ArgumentNullException("task"); | |
if (next == null) throw new ArgumentNullException("next"); | |
var tcs = new TaskCompletionSource<AsyncVoid>(); | |
Action<Task<TResult>> a = previousTask => | |
{ | |
if (previousTask.IsFaulted) tcs.TrySetException(previousTask.Exception); | |
else if (previousTask.IsCanceled) tcs.TrySetCanceled(); | |
else | |
{ | |
try | |
{ | |
next(previousTask); | |
tcs.TrySetResult(default(AsyncVoid)); | |
} | |
catch (Exception ex) | |
{ | |
tcs.TrySetException(ex); | |
} | |
} | |
}; | |
task.ContinueWith(a); | |
return tcs.Task; | |
} | |
public static Task Then<TResult>(this Task<TResult> task, Func<Task<TResult>, Task> next) | |
{ | |
if (task == null) throw new ArgumentNullException("task"); | |
if (next == null) throw new ArgumentNullException("next"); | |
var tcs = new TaskCompletionSource<AsyncVoid>(); | |
Action<Task<TResult>> a = previousTask => | |
{ | |
if (previousTask.IsFaulted) tcs.TrySetException(previousTask.Exception); | |
else if (previousTask.IsCanceled) tcs.TrySetCanceled(); | |
else | |
{ | |
try | |
{ | |
next(previousTask).ContinueWith(nextTask => | |
{ | |
if (nextTask.IsFaulted) tcs.TrySetException(nextTask.Exception); | |
else if (nextTask.IsCanceled) tcs.TrySetCanceled(); | |
else tcs.TrySetResult(default(AsyncVoid)); | |
}); | |
} | |
catch (Exception ex) | |
{ | |
tcs.TrySetException(ex); | |
} | |
} | |
}; | |
task.ContinueWith(a); | |
return tcs.Task; | |
} | |
public static Task<TNextResult> Then<TResult, TNextResult>(this Task<TResult> task, Func<Task<TResult>, TNextResult> next) | |
{ | |
if (task == null) throw new ArgumentNullException("task"); | |
if (next == null) throw new ArgumentNullException("next"); | |
var tcs = new TaskCompletionSource<TNextResult>(); | |
Action<Task<TResult>> a = previousTask => | |
{ | |
if (previousTask.IsFaulted) tcs.TrySetException(previousTask.Exception); | |
else if (previousTask.IsCanceled) tcs.TrySetCanceled(); | |
else | |
{ | |
try | |
{ | |
tcs.TrySetResult(next(previousTask)); | |
} | |
catch (Exception ex) | |
{ | |
tcs.TrySetException(ex); | |
} | |
} | |
}; | |
task.ContinueWith(a); | |
return tcs.Task; | |
} | |
public static Task<TNextResult> Then<TResult, TNextResult>(this Task<TResult> task, Func<Task<TResult>, Task<TNextResult>> next) | |
{ | |
if (task == null) throw new ArgumentNullException("task"); | |
if (next == null) throw new ArgumentNullException("next"); | |
var tcs = new TaskCompletionSource<TNextResult>(); | |
Action<Task<TResult>> a = previousTask => | |
{ | |
if (previousTask.IsFaulted) tcs.TrySetException(previousTask.Exception); | |
else if (previousTask.IsCanceled) tcs.TrySetCanceled(); | |
else | |
{ | |
try | |
{ | |
Action<Task<TNextResult>> b = nextTask => | |
{ | |
if (nextTask.IsFaulted) tcs.TrySetException(nextTask.Exception); | |
else if (nextTask.IsCanceled) tcs.TrySetCanceled(); | |
else | |
{ | |
try | |
{ | |
tcs.TrySetResult(nextTask.Result); | |
} | |
catch (Exception ex) | |
{ | |
tcs.TrySetException(ex); | |
} | |
} | |
}; | |
next(previousTask).ContinueWith(b); | |
} | |
catch (Exception ex) | |
{ | |
tcs.TrySetException(ex); | |
} | |
} | |
}; | |
task.ContinueWith(a); | |
return tcs.Task; | |
} | |
/// <summary> | |
/// Analogous to the finally block in a try/finally | |
/// </summary> | |
public static void Finally(this Task task, Action<Exception> exceptionHandler, Action finalAction = null) | |
{ | |
task.ContinueWith(t => { | |
if (finalAction != null) finalAction(); | |
if (t.IsCanceled || !t.IsFaulted || exceptionHandler == null) return; | |
var innerException = t.Exception.Flatten().InnerExceptions.FirstOrDefault(); | |
exceptionHandler(innerException ?? t.Exception); | |
}); | |
} | |
} | |
public struct AsyncVoid | |
{ | |
// Based on Brad Wilson's idea, to simulate a non-generic TaskCompletionSource | |
// http://bradwilson.typepad.com/blog/2012/04/tpl-and-servers-pt4.html | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment