File: System\Runtime\TaskExtensions.cs
Project: ndp\cdf\src\System.ServiceModel.Internals\System.ServiceModel.Internals.csproj (System.ServiceModel.Internals)
// <copyright>
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
 
namespace System.Runtime
{
    using System.Runtime.CompilerServices;
    using System.Threading;
    using System.Threading.Tasks;
 
    internal static class TaskExtensions
    {
        public static IAsyncResult AsAsyncResult<T>(this Task<T> task, AsyncCallback callback, object state)
        {
            if (task == null)
            {
                throw Fx.Exception.ArgumentNull("task");
            }
 
            if (task.Status == TaskStatus.Created)
            {
                throw Fx.Exception.AsError(new InvalidOperationException(InternalSR.SFxTaskNotStarted));
            }
 
            var tcs = new TaskCompletionSource<T>(state);
 
            task.ContinueWith(
                t =>
                {
                    if (t.IsFaulted)
                    {
                        tcs.TrySetException(t.Exception.InnerExceptions);
                    }
                    else if (t.IsCanceled)
                    {
                        // the use of Task.ContinueWith(,TaskContinuationOptions.OnlyOnRanToCompletion)
                        // can give us a cancelled Task here with no t.Exception.
                        tcs.TrySetCanceled();
                    }
                    else
                    {
                        tcs.TrySetResult(t.Result);
                    }
 
                    if (callback != null)
                    {
                        callback(tcs.Task);
                    }
                }, 
                TaskContinuationOptions.ExecuteSynchronously);
 
            return tcs.Task;
        }
 
        public static IAsyncResult AsAsyncResult(this Task task, AsyncCallback callback, object state)
        {
            if (task == null)
            {
                throw Fx.Exception.ArgumentNull("task");
            }
 
            if (task.Status == TaskStatus.Created)
            {
                throw Fx.Exception.AsError(new InvalidOperationException(InternalSR.SFxTaskNotStarted));
            }
 
            var tcs = new TaskCompletionSource<object>(state);
 
            task.ContinueWith(
                t =>
                {
                    if (t.IsFaulted)
                    {
                        tcs.TrySetException(t.Exception.InnerExceptions);
                    }
                    else if (t.IsCanceled)
                    {
                        // the use of Task.ContinueWith(,TaskContinuationOptions.OnlyOnRanToCompletion)
                        // can give us a cancelled Task here with no t.Exception.
                        tcs.TrySetCanceled();
                    }
                    else
                    {
                        tcs.TrySetResult(null);
                    }
 
                    if (callback != null)
                    {
                        callback(tcs.Task);
                    }
                }, 
                TaskContinuationOptions.ExecuteSynchronously);
 
            return tcs.Task;
        }
 
        public static ConfiguredTaskAwaitable SuppressContextFlow(this Task task)
        {
            return task.ConfigureAwait(false);
        }
 
        public static ConfiguredTaskAwaitable<T> SuppressContextFlow<T>(this Task<T> task)
        {
            return task.ConfigureAwait(false);
        }
 
        public static ConfiguredTaskAwaitable ContinueOnCapturedContextFlow(this Task task)
        {
            return task.ConfigureAwait(true);
        }
 
        public static ConfiguredTaskAwaitable<T> ContinueOnCapturedContextFlow<T>(this Task<T> task)
        {
            return task.ConfigureAwait(true);
        }
 
        public static void Wait<TException>(this Task task)
        {
            try
            {
                task.Wait();
            }
            catch (AggregateException ex)
            {
                throw Fx.Exception.AsError<TException>(ex);
            }
        }
 
        public static bool Wait<TException>(this Task task, int millisecondsTimeout)
        {
            try
            {
                return task.Wait(millisecondsTimeout);
            }
            catch (AggregateException ex)
            {
                throw Fx.Exception.AsError<TException>(ex);
            }
        }
 
        public static bool Wait<TException>(this Task task, TimeSpan timeout)
        {
            try
            {
                if (timeout == TimeSpan.MaxValue)
                {
                    return task.Wait(Timeout.Infinite);
                }
                else
                {
                    return task.Wait(timeout);
                }
            }
            catch (AggregateException ex)
            {
                throw Fx.Exception.AsError<TException>(ex);
            }
        }
 
        public static void Wait(this Task task, TimeSpan timeout, Action<Exception, TimeSpan, string> exceptionConverter, string operationType)
        {
            bool timedOut = false;
 
            try
            {
                if (timeout > TimeoutHelper.MaxWait)
                {
                    task.Wait();
                }
                else
                {
                    timedOut = !task.Wait(timeout);
                }
            }
            catch (Exception ex)
            {
                if (Fx.IsFatal(ex) || exceptionConverter == null)
                {
                    throw;
                }
 
                exceptionConverter(ex, timeout, operationType);
            }
 
            if (timedOut)
            {
                throw Fx.Exception.AsError(new TimeoutException(InternalSR.TaskTimedOutError(timeout)));
            }
        }
 
        public static Task<TBase> Upcast<TDerived, TBase>(this Task<TDerived> task) where TDerived : TBase
        {
            return (task.Status == TaskStatus.RanToCompletion) ?
                Task.FromResult((TBase)task.Result) :
                UpcastPrivate<TDerived, TBase>(task);
        }
 
        private static async Task<TBase> UpcastPrivate<TDerived, TBase>(this Task<TDerived> task) where TDerived : TBase
        {
            return await task.ConfigureAwait(false);
        }
    }
}