// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Linq; namespace System.Threading.Tasks { static class TaskExt { public static Task Return(T value, CancellationToken cancellationToken) { var tcs = new TaskCompletionSource(); tcs.TrySetResult(value); return tcs.Task; } public static Task Throw(Exception exception, CancellationToken cancellationToken) { var tcs = new TaskCompletionSource(); tcs.TrySetException(exception); return tcs.Task; } public static void Handle(this Task task, TaskCompletionSource tcs, Action success) { Handle(task, tcs, success, ex => tcs.TrySetException(ex), () => tcs.TrySetCanceled()); } public static void Handle(this Task task, TaskCompletionSource tcs, Action success, Action error) { Handle(task, tcs, success, error, () => tcs.TrySetCanceled()); } public static void Handle(this Task task, TaskCompletionSource tcs, Action success, Action error, Action canceled) { if (task.IsFaulted) error(task.Exception); else if (task.IsCanceled) canceled(); else if (task.IsCompleted) success(task.Result); } public static Task UsingEnumerator(this Task task, IDisposable disposable) { task.ContinueWith(t => { if (t.IsFaulted) { var ignored = t.Exception; // don't remove! } if (t.IsFaulted || t.IsCanceled || !t.Result) disposable.Dispose(); }, TaskContinuationOptions.ExecuteSynchronously); return task; } public static Task UsingEnumeratorSync(this Task task, IDisposable disposable) { var tcs = new TaskCompletionSource(); task.ContinueWith(t => { if (t.IsFaulted || t.IsCanceled || !t.Result) disposable.Dispose(); // TODO: Check whether we need exception handling here! t.Handle(tcs, res => tcs.TrySetResult(res)); }, TaskContinuationOptions.ExecuteSynchronously); return tcs.Task; } public static Task Finally(this Task task, Action action) { task.ContinueWith(t => { if (t.IsFaulted) { var ignored = t.Exception; // don't remove! } action(); }, TaskContinuationOptions.ExecuteSynchronously); return task; } public static Task Zip(this Task t1, Task t2, Func f) { var gate = new object(); var tcs = new TaskCompletionSource(); var i = 2; var complete = new Action(t => { if (Interlocked.Decrement(ref i) == 0) { var exs = new List(); if (t1.IsFaulted) exs.Add(t1.Exception); if (t2.IsFaulted) exs.Add(t2.Exception); if (exs.Count > 0) tcs.TrySetException(exs); else if (t1.IsCanceled || t2.IsCanceled) tcs.TrySetCanceled(); else { var res = default(V); try { res = f(t1.Result, t2.Result); } catch (Exception ex) { tcs.TrySetException(ex); return; } tcs.TrySetResult(res); } } }); t1.ContinueWith(complete); t2.ContinueWith(complete); return tcs.Task; } } }