TaskExtensions.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / System / Threading / Tasks / TaskExtensions.cs / 1305376 / TaskExtensions.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// 
// TaskExtensions.cs 
//
// [....] 
//
// Extensions to Task/Task classes
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 

using System; 
using System.Collections.Generic; 
using System.Threading;
using System.Threading.Tasks; 
using System.Diagnostics.Contracts;

namespace System.Threading.Tasks
{ 
    /// 
    /// Provides a set of static (Shared in Visual Basic) methods for working with specific kinds of 
    ///  instances. 
    /// 
    public static class TaskExtensions 
    {
        /// 
        /// Creates a proxy Task that represents the
        /// asynchronous operation of a Task{Task}. 
        /// 
        ///  
        /// It is often useful to be able to return a Task from a  
        /// Task{TResult}, where the inner Task represents work done as part of the outer Task{TResult}.  However,
        /// doing so results in a Task{Task}, which, if not dealt with carefully, could produce unexpected behavior.  Unwrap 
        /// solves this problem by creating a proxy Task that represents the entire asynchronous operation of such a Task{Task}.
        /// 
        /// The Task{Task} to unwrap.
        /// The exception that is thrown if the 
        ///  argument is null.
        /// A Task that represents the asynchronous operation of the provided Task{Task}. 
        public static Task Unwrap(this Task task) 
        {
            if (task == null) throw new ArgumentNullException("task"); 
            bool result;

            // tcs.Task serves as a proxy for task.Result.
            // AttachedToParent is the only legal option for TCS-style task. 
            var tcs = new TaskCompletionSource(task.CreationOptions & TaskCreationOptions.AttachedToParent);
 
            // Set up some actions to take when task has completed. 
            task.ContinueWith(delegate
            { 
                switch (task.Status)
                {
                    // If task did not run to completion, then record the cancellation/fault information
                    // to tcs.Task. 
                    case TaskStatus.Canceled:
                    case TaskStatus.Faulted: 
                        result = tcs.TrySetFromTask(task); 
                        Contract.Assert(result, "Unwrap(Task): Expected TrySetFromTask #1 to succeed");
                        break; 

                    case TaskStatus.RanToCompletion:
                        // task.Result == null ==> proxy should be canceled.
                        if (task.Result == null) tcs.TrySetCanceled(); 

                        // When task.Result completes, take some action to set the completion state of tcs.Task. 
                        else 
                        {
                            task.Result.ContinueWith(_ => 
                            {
                                // Copy completion/cancellation/exception info from task.Result to tcs.Task.
                                result = tcs.TrySetFromTask(task.Result);
                                Contract.Assert(result, "Unwrap(Task): Expected TrySetFromTask #2 to succeed"); 
                            }, TaskContinuationOptions.ExecuteSynchronously).ContinueWith(antecedent =>
                            { 
                                // Clean up if ContinueWith() operation fails due to TSE 
                                tcs.TrySetException(antecedent.Exception);
                            }, TaskContinuationOptions.OnlyOnFaulted); 
                        }
                        break;
                }
            }, TaskContinuationOptions.ExecuteSynchronously).ContinueWith(antecedent => 
            {
                // Clean up if ContinueWith() operation fails due to TSE 
                tcs.TrySetException(antecedent.Exception); 
            }, TaskContinuationOptions.OnlyOnFaulted);
 
            // Return this immediately as a proxy.  When task.Result completes, or task is faulted/canceled,
            // the completion information will be transfered to tcs.Task.
            return tcs.Task;
        } 

        ///  
        /// Creates a proxy Task{TResult} that represents the 
        /// asynchronous operation of a Task{Task{TResult}}.
        ///  
        /// 
        /// It is often useful to be able to return a Task{TResult} from a Task{TResult}, where the inner Task{TResult}
        /// represents work done as part of the outer Task{TResult}.  However, doing so results in a Task{Task{TResult}},
        /// which, if not dealt with carefully, could produce unexpected behavior.  Unwrap solves this problem by 
        /// creating a proxy Task{TResult} that represents the entire asynchronous operation of such a Task{Task{TResult}}.
        ///  
        /// The Task{Task{TResult}} to unwrap. 
        /// The exception that is thrown if the
        ///  argument is null. 
        /// A Task{TResult} that represents the asynchronous operation of the provided Task{Task{TResult}}.        /// Unwraps a Task that returns another Task.
        public static Task Unwrap(this Task> task)
        {
            if (task == null) throw new ArgumentNullException("task"); 
            bool result;
 
            // tcs.Task serves as a proxy for task.Result. 
            // AttachedToParent is the only legal option for TCS-style task.
            var tcs = new TaskCompletionSource(task.CreationOptions & TaskCreationOptions.AttachedToParent); 

            // Set up some actions to take when task has completed.
            task.ContinueWith(delegate
            { 
                switch (task.Status)
                { 
                    // If task did not run to completion, then record the cancellation/fault information 
                    // to tcs.Task.
                    case TaskStatus.Canceled: 
                    case TaskStatus.Faulted:
                        result = tcs.TrySetFromTask(task);
                        Contract.Assert(result, "Unwrap(Task>): Expected TrySetFromTask #1 to succeed");
                        break; 

                    case TaskStatus.RanToCompletion: 
                        // task.Result == null ==> proxy should be canceled. 
                        if (task.Result == null) tcs.TrySetCanceled();
 
                        // When task.Result completes, take some action to set the completion state of tcs.Task.
                        else
                        {
                            task.Result.ContinueWith(_ => 
                            {
                                // Copy completion/cancellation/exception info from task.Result to tcs.Task. 
                                result = tcs.TrySetFromTask(task.Result); 
                                Contract.Assert(result, "Unwrap(Task>): Expected TrySetFromTask #2 to succeed");
                            }, 
                            TaskContinuationOptions.ExecuteSynchronously).ContinueWith(antecedent =>
                            {
                                // Clean up if ContinueWith() operation fails due to TSE
                                tcs.TrySetException(antecedent.Exception); 
                            }, TaskContinuationOptions.OnlyOnFaulted);
                        } 
 
                        break;
                } 
            }, TaskContinuationOptions.ExecuteSynchronously).ContinueWith(antecedent =>
            {
                // Clean up if ContinueWith() operation fails due to TSE
                tcs.TrySetException(antecedent.Exception); 
            }, TaskContinuationOptions.OnlyOnFaulted); ;
 
            // Return this immediately as a proxy.  When task.Result completes, or task is faulted/canceled, 
            // the completion information will be transfered to tcs.Task.
            return tcs.Task; 
        }

        // Transfer the completion status from "source" to "me".
        private static bool TrySetFromTask(this TaskCompletionSource me, Task source) 
        {
            Contract.Assert(source.IsCompleted, "TrySetFromTask: Expected source to have completed."); 
            bool rval = false; 

            switch(source.Status) 
            {
                case TaskStatus.Canceled:
                    rval = me.TrySetCanceled();
                    break; 

                case TaskStatus.Faulted: 
                    rval = me.TrySetException(source.Exception.InnerExceptions); 
                    break;
 
                case TaskStatus.RanToCompletion:
                    if(source is Task)
                        rval = me.TrySetResult( ((Task)source).Result);
                    else 
                        rval = me.TrySetResult(default(TResult));
                    break; 
            } 

            return rval; 
        }

    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK