// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // // // There are a plethora of common patterns for which Tasks are created. TaskFactory encodes // these patterns into helper methods. These helpers also pick up default configuration settings // applicable to the entire factory and configurable through its constructors. // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- using System; using System.Collections.Generic; using System.Security; using System.Runtime.CompilerServices; using System.Threading; using System.Diagnostics; namespace System.Threading.Tasks { /// /// Provides support for creating and scheduling /// Tasks. /// /// /// /// There are many common patterns for which tasks are relevant. The /// class encodes some of these patterns into methods that pick up default settings, which are /// configurable through its constructors. /// /// /// A default instance of is available through the /// Task.Factory property. /// /// public class TaskFactory { // member variables private readonly CancellationToken m_defaultCancellationToken; private readonly TaskScheduler m_defaultScheduler; private readonly TaskCreationOptions m_defaultCreationOptions; private readonly TaskContinuationOptions m_defaultContinuationOptions; private TaskScheduler DefaultScheduler => m_defaultScheduler ?? TaskScheduler.Current; // sister method to above property -- avoids a TLS lookup private TaskScheduler GetDefaultScheduler(Task currTask) { return m_defaultScheduler ?? (currTask != null && (currTask.CreationOptions & TaskCreationOptions.HideScheduler) == 0 ? currTask.ExecutingTaskScheduler : TaskScheduler.Default); } /* Constructors */ // ctor parameters provide defaults for the factory, which can be overridden by options provided to // specific calls on the factory /// /// Initializes a instance with the default configuration. /// /// /// This constructor creates a instance with a default configuration. The /// property is initialized to /// TaskCreationOptions.None, the /// property is initialized to TaskContinuationOptions.None, /// and the TaskScheduler property is /// initialized to the current scheduler (see TaskScheduler.Current). /// public TaskFactory() : this(default, TaskCreationOptions.None, TaskContinuationOptions.None, null) { } /// /// Initializes a instance with the specified configuration. /// /// The default that will be assigned /// to tasks created by this unless another CancellationToken is explicitly specified /// while calling the factory methods. /// /// This constructor creates a instance with a default configuration. The /// property is initialized to /// TaskCreationOptions.None, the /// property is initialized to TaskContinuationOptions.None, /// and the TaskScheduler property is /// initialized to the current scheduler (see TaskScheduler.Current). /// public TaskFactory(CancellationToken cancellationToken) : this(cancellationToken, TaskCreationOptions.None, TaskContinuationOptions.None, null) { } /// /// Initializes a instance with the specified configuration. /// /// /// The /// TaskScheduler to use to schedule any tasks created with this TaskFactory. A null value /// indicates that the current TaskScheduler should be used. /// /// /// With this constructor, the /// property is initialized to /// TaskCreationOptions.None, the /// property is initialized to TaskContinuationOptions.None, /// and the TaskScheduler property is /// initialized to , unless it's null, in which case the property is /// initialized to the current scheduler (see TaskScheduler.Current). /// public TaskFactory(TaskScheduler scheduler) // null means to use TaskScheduler.Current : this(default, TaskCreationOptions.None, TaskContinuationOptions.None, scheduler) { } /// /// Initializes a instance with the specified configuration. /// /// /// The default /// TaskCreationOptions to use when creating tasks with this TaskFactory. /// /// /// The default /// TaskContinuationOptions to use when creating continuation tasks with this TaskFactory. /// /// /// The exception that is thrown when the /// argument or the /// argument specifies an invalid value. /// /// /// With this constructor, the /// property is initialized to , /// the /// property is initialized to , and the TaskScheduler property is initialized to the /// current scheduler (see TaskScheduler.Current). /// public TaskFactory(TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions) : this(default, creationOptions, continuationOptions, null) { } /// /// Initializes a instance with the specified configuration. /// /// The default that will be assigned /// to tasks created by this unless another CancellationToken is explicitly specified /// while calling the factory methods. /// /// The default /// TaskCreationOptions to use when creating tasks with this TaskFactory. /// /// /// The default /// TaskContinuationOptions to use when creating continuation tasks with this TaskFactory. /// /// /// The default /// TaskScheduler to use to schedule any Tasks created with this TaskFactory. A null value /// indicates that TaskScheduler.Current should be used. /// /// /// The exception that is thrown when the /// argument or the /// argumentspecifies an invalid value. /// /// /// With this constructor, the /// property is initialized to , /// the /// property is initialized to , and the TaskScheduler property is initialized to /// , unless it's null, in which case the property is initialized to the /// current scheduler (see TaskScheduler.Current). /// public TaskFactory(CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { CheckMultiTaskContinuationOptions(continuationOptions); CheckCreationOptions(creationOptions); m_defaultCancellationToken = cancellationToken; m_defaultScheduler = scheduler; m_defaultCreationOptions = creationOptions; m_defaultContinuationOptions = continuationOptions; } internal static void CheckCreationOptions(TaskCreationOptions creationOptions) { // Check for validity of options if ((creationOptions & ~(TaskCreationOptions.AttachedToParent | TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler | TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness | TaskCreationOptions.RunContinuationsAsynchronously)) != 0) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.creationOptions); } } /* Properties */ /// /// Gets the default CancellationToken of this /// TaskFactory. /// /// /// This property returns the default that will be assigned to all /// tasks created by this factory unless another CancellationToken value is explicitly specified /// during the call to the factory methods. /// public CancellationToken CancellationToken { get { return m_defaultCancellationToken; } } /// /// Gets the TaskScheduler of this /// TaskFactory. /// /// /// This property returns the default scheduler for this factory. It will be used to schedule all /// tasks unless another scheduler is explicitly specified during calls to this factory's methods. /// If null, TaskScheduler.Current /// will be used. /// public TaskScheduler Scheduler { get { return m_defaultScheduler; } } /// /// Gets the TaskCreationOptions /// value of this TaskFactory. /// /// /// This property returns the default creation options for this factory. They will be used to create all /// tasks unless other options are explicitly specified during calls to this factory's methods. /// public TaskCreationOptions CreationOptions { get { return m_defaultCreationOptions; } } /// /// Gets the TaskContinuationOptions /// value of this TaskFactory. /// /// /// This property returns the default continuation options for this factory. They will be used to create /// all continuation tasks unless other options are explicitly specified during calls to this factory's methods. /// public TaskContinuationOptions ContinuationOptions { get { return m_defaultContinuationOptions; } } // // StartNew methods // /// /// Creates and starts a Task. /// /// The action delegate to execute asynchronously. /// The started Task. /// The exception that is thrown when the /// argument is null. /// /// Calling StartNew is functionally equivalent to creating a Task using one of its constructors /// and then calling /// Start to schedule it for execution. However, /// unless creation and scheduling must be separated, StartNew is the recommended /// approach for both simplicity and performance. /// public Task StartNew(Action action) { Task currTask = Task.InternalCurrent; return Task.InternalStartNew(currTask, action, null, m_defaultCancellationToken, GetDefaultScheduler(currTask), m_defaultCreationOptions, InternalTaskOptions.None); } /// /// Creates and starts a Task. /// /// The action delegate to execute asynchronously. /// The that will be assigned to the new task. /// The started Task. /// The exception that is thrown when the /// argument is null. /// The provided CancellationToken /// has already been disposed. /// /// /// Calling StartNew is functionally equivalent to creating a Task using one of its constructors /// and then calling /// Start to schedule it for execution. However, /// unless creation and scheduling must be separated, StartNew is the recommended /// approach for both simplicity and performance. /// public Task StartNew(Action action, CancellationToken cancellationToken) { Task currTask = Task.InternalCurrent; return Task.InternalStartNew(currTask, action, null, cancellationToken, GetDefaultScheduler(currTask), m_defaultCreationOptions, InternalTaskOptions.None); } /// /// Creates and starts a Task. /// /// The action delegate to execute asynchronously. /// A TaskCreationOptions value that controls the behavior of the /// created /// Task. /// The started Task. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// /// Calling StartNew is functionally equivalent to creating a Task using one of its constructors and /// then calling /// Start to schedule it for execution. /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// public Task StartNew(Action action, TaskCreationOptions creationOptions) { Task currTask = Task.InternalCurrent; return Task.InternalStartNew(currTask, action, null, m_defaultCancellationToken, GetDefaultScheduler(currTask), creationOptions, InternalTaskOptions.None); } /// /// Creates and starts a Task. /// /// The action delegate to execute asynchronously. /// The that will be assigned to the new /// A TaskCreationOptions value that controls the behavior of the /// created /// Task. /// The TaskScheduler /// that is used to schedule the created Task. /// The started Task. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// The provided CancellationToken /// has already been disposed. /// /// /// Calling StartNew is functionally equivalent to creating a Task using one of its constructors and /// then calling /// Start to schedule it for execution. /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// public Task StartNew(Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) { return Task.InternalStartNew( Task.InternalCurrentIfAttached(creationOptions), action, null, cancellationToken, scheduler, creationOptions, InternalTaskOptions.None); } /// /// Creates and starts a Task. /// /// The action delegate to execute asynchronously. /// An object containing data to be used by the /// delegate. /// The started Task. /// The exception that is thrown when the /// argument is null. /// /// Calling StartNew is functionally equivalent to creating a Task using one of its constructors and /// then calling /// Start to schedule it for execution. /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// public Task StartNew(Action action, object state) { Task currTask = Task.InternalCurrent; return Task.InternalStartNew(currTask, action, state, m_defaultCancellationToken, GetDefaultScheduler(currTask), m_defaultCreationOptions, InternalTaskOptions.None); } /// /// Creates and starts a Task. /// /// The action delegate to execute asynchronously. /// An object containing data to be used by the /// delegate. /// The that will be assigned to the new /// The started Task. /// The exception that is thrown when the /// argument is null. /// The provided CancellationToken /// has already been disposed. /// /// /// Calling StartNew is functionally equivalent to creating a Task using one of its constructors and /// then calling /// Start to schedule it for execution. /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// public Task StartNew(Action action, object state, CancellationToken cancellationToken) { Task currTask = Task.InternalCurrent; return Task.InternalStartNew(currTask, action, state, cancellationToken, GetDefaultScheduler(currTask), m_defaultCreationOptions, InternalTaskOptions.None); } /// /// Creates and starts a Task. /// /// The action delegate to execute asynchronously. /// An object containing data to be used by the /// delegate. /// A TaskCreationOptions value that controls the behavior of the /// created /// Task. /// The started Task. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// /// Calling StartNew is functionally equivalent to creating a Task using one of its constructors and /// then calling /// Start to schedule it for execution. /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// public Task StartNew(Action action, object state, TaskCreationOptions creationOptions) { Task currTask = Task.InternalCurrent; return Task.InternalStartNew(currTask, action, state, m_defaultCancellationToken, GetDefaultScheduler(currTask), creationOptions, InternalTaskOptions.None); } /// /// Creates and starts a Task. /// /// The action delegate to execute asynchronously. /// An object containing data to be used by the /// delegate. /// The that will be assigned to the new task. /// A TaskCreationOptions value that controls the behavior of the /// created /// Task. /// The TaskScheduler /// that is used to schedule the created Task. /// The started Task. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// The provided CancellationToken /// has already been disposed. /// /// /// Calling StartNew is functionally equivalent to creating a Task using one of its constructors and /// then calling /// Start to schedule it for execution. /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// public Task StartNew(Action action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) { return Task.InternalStartNew( Task.InternalCurrentIfAttached(creationOptions), action, state, cancellationToken, scheduler, creationOptions, InternalTaskOptions.None); } /// /// Creates and starts a . /// /// The type of the result available through the /// Task. /// /// A function delegate that returns the future result to be available through /// the . /// The started . /// The exception that is thrown when the /// argument is null. /// /// Calling StartNew is functionally equivalent to creating a using one /// of its constructors and then calling /// Start to schedule it for execution. /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// public Task StartNew(Func function) { Task currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, m_defaultCancellationToken, m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } /// /// Creates and starts a . /// /// The type of the result available through the /// Task. /// /// A function delegate that returns the future result to be available through /// the . /// The that will be assigned to the new /// The started . /// The exception that is thrown when the /// argument is null. /// The provided CancellationToken /// has already been disposed. /// /// /// Calling StartNew is functionally equivalent to creating a using one /// of its constructors and then calling /// Start to schedule it for execution. /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// public Task StartNew(Func function, CancellationToken cancellationToken) { Task currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, cancellationToken, m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } /// /// Creates and starts a . /// /// The type of the result available through the /// Task. /// /// A function delegate that returns the future result to be available through /// the . /// A TaskCreationOptions value that controls the behavior of the /// created /// . /// The started . /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// /// Calling StartNew is functionally equivalent to creating a using one /// of its constructors and then calling /// Start to schedule it for execution. /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// public Task StartNew(Func function, TaskCreationOptions creationOptions) { Task currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, m_defaultCancellationToken, creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } /// /// Creates and starts a . /// /// The type of the result available through the /// Task. /// /// A function delegate that returns the future result to be available through /// the . /// The that will be assigned to the new task. /// A TaskCreationOptions value that controls the behavior of the /// created /// . /// The TaskScheduler /// that is used to schedule the created /// Task{TResult}. /// The started . /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// The provided CancellationToken /// has already been disposed. /// /// /// Calling StartNew is functionally equivalent to creating a using one /// of its constructors and then calling /// Start to schedule it for execution. /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// public Task StartNew(Func function, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) { return Task.StartNew( Task.InternalCurrentIfAttached(creationOptions), function, cancellationToken, creationOptions, InternalTaskOptions.None, scheduler); } /// /// Creates and starts a . /// /// The type of the result available through the /// Task. /// /// A function delegate that returns the future result to be available through /// the . /// An object containing data to be used by the /// delegate. /// The started . /// The exception that is thrown when the /// argument is null. /// /// Calling StartNew is functionally equivalent to creating a using one /// of its constructors and then calling /// Start to schedule it for execution. /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// public Task StartNew(Func function, object state) { Task currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, state, m_defaultCancellationToken, m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } /// /// Creates and starts a . /// /// The type of the result available through the /// Task. /// /// A function delegate that returns the future result to be available through /// the . /// An object containing data to be used by the /// delegate. /// The that will be assigned to the new /// The started . /// The exception that is thrown when the /// argument is null. /// The provided CancellationToken /// has already been disposed. /// /// /// Calling StartNew is functionally equivalent to creating a using one /// of its constructors and then calling /// Start to schedule it for execution. /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// public Task StartNew(Func function, object state, CancellationToken cancellationToken) { Task currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, state, cancellationToken, m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } /// /// Creates and starts a . /// /// The type of the result available through the /// Task. /// /// A function delegate that returns the future result to be available through /// the . /// An object containing data to be used by the /// delegate. /// A TaskCreationOptions value that controls the behavior of the /// created /// . /// The started . /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// /// Calling StartNew is functionally equivalent to creating a using one /// of its constructors and then calling /// Start to schedule it for execution. /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// public Task StartNew(Func function, object state, TaskCreationOptions creationOptions) { Task currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, state, m_defaultCancellationToken, creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } /// /// Creates and starts a . /// /// The type of the result available through the /// Task. /// /// A function delegate that returns the future result to be available through /// the . /// An object containing data to be used by the /// delegate. /// The that will be assigned to the new task. /// A TaskCreationOptions value that controls the behavior of the /// created /// . /// The TaskScheduler /// that is used to schedule the created /// Task{TResult}. /// The started . /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// The provided CancellationToken /// has already been disposed. /// /// /// Calling StartNew is functionally equivalent to creating a using one /// of its constructors and then calling /// Start to schedule it for execution. /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// public Task StartNew(Func function, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) { return Task.StartNew( Task.InternalCurrentIfAttached(creationOptions), function, state, cancellationToken, creationOptions, InternalTaskOptions.None, scheduler); } // // FromAsync methods // /// /// Creates a Task that executes an end method action /// when a specified IAsyncResult completes. /// /// The IAsyncResult whose completion should trigger the processing of the /// . /// The action delegate that processes the completed . /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// A Task that represents the asynchronous /// operation. public Task FromAsync( IAsyncResult asyncResult, Action endMethod) { return FromAsync(asyncResult, endMethod, m_defaultCreationOptions, DefaultScheduler); } /// /// Creates a Task that executes an end method action /// when a specified IAsyncResult completes. /// /// The IAsyncResult whose completion should trigger the processing of the /// . /// The action delegate that processes the completed . /// The TaskCreationOptions value that controls the behavior of the /// created Task. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// A Task that represents the asynchronous /// operation. public Task FromAsync( IAsyncResult asyncResult, Action endMethod, TaskCreationOptions creationOptions) { return FromAsync(asyncResult, endMethod, creationOptions, DefaultScheduler); } /// /// Creates a Task that executes an end method action /// when a specified IAsyncResult completes. /// /// The IAsyncResult whose completion should trigger the processing of the /// . /// The action delegate that processes the completed . /// The TaskScheduler /// that is used to schedule the task that executes the end method. /// The TaskCreationOptions value that controls the behavior of the /// created Task. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// A Task that represents the asynchronous /// operation. public Task FromAsync( IAsyncResult asyncResult, Action endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler) { return TaskFactory.FromAsyncImpl(asyncResult, null, endMethod, creationOptions, scheduler); } /// /// Creates a Task that represents a pair of begin /// and end methods that conform to the Asynchronous Programming Model pattern. /// /// The delegate that begins the asynchronous operation. /// The delegate that ends the asynchronous operation. /// An object containing data to be used by the /// delegate. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The created Task that represents the /// asynchronous operation. /// /// This method throws any exceptions thrown by the . /// public Task FromAsync( Func beginMethod, Action endMethod, object state) { return FromAsync(beginMethod, endMethod, state, m_defaultCreationOptions); } /// /// Creates a Task that represents a pair of begin /// and end methods that conform to the Asynchronous Programming Model pattern. /// /// The delegate that begins the asynchronous operation. /// The delegate that ends the asynchronous operation. /// The TaskCreationOptions value that controls the behavior of the /// created Task. /// An object containing data to be used by the /// delegate. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// The created Task that represents the /// asynchronous operation. /// /// This method throws any exceptions thrown by the . /// public Task FromAsync( Func beginMethod, Action endMethod, object state, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(beginMethod, null, endMethod, state, creationOptions); } /// /// Creates a Task that represents a pair of begin /// and end methods that conform to the Asynchronous Programming Model pattern. /// /// The type of the first argument passed to the /// delegate. /// The delegate that begins the asynchronous operation. /// The delegate that ends the asynchronous operation. /// The first argument passed to the /// delegate. /// An object containing data to be used by the /// delegate. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The created Task that represents the /// asynchronous operation. /// /// This method throws any exceptions thrown by the . /// public Task FromAsync( Func beginMethod, Action endMethod, TArg1 arg1, object state) { return FromAsync(beginMethod, endMethod, arg1, state, m_defaultCreationOptions); } /// /// Creates a Task that represents a pair of begin /// and end methods that conform to the Asynchronous Programming Model pattern. /// /// The type of the first argument passed to the /// delegate. /// The delegate that begins the asynchronous operation. /// The delegate that ends the asynchronous operation. /// The first argument passed to the /// delegate. /// The TaskCreationOptions value that controls the behavior of the /// created Task. /// An object containing data to be used by the /// delegate. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// The created Task that represents the /// asynchronous operation. /// /// This method throws any exceptions thrown by the . /// public Task FromAsync( Func beginMethod, Action endMethod, TArg1 arg1, object state, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(beginMethod, null, endMethod, arg1, state, creationOptions); } /// /// Creates a Task that represents a pair of begin /// and end methods that conform to the Asynchronous Programming Model pattern. /// /// The type of the first argument passed to the /// delegate. /// The type of the second argument passed to /// delegate. /// The delegate that begins the asynchronous operation. /// The delegate that ends the asynchronous operation. /// The first argument passed to the /// delegate. /// The second argument passed to the /// delegate. /// An object containing data to be used by the /// delegate. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The created Task that represents the /// asynchronous operation. /// /// This method throws any exceptions thrown by the . /// public Task FromAsync( Func beginMethod, Action endMethod, TArg1 arg1, TArg2 arg2, object state) { return FromAsync(beginMethod, endMethod, arg1, arg2, state, m_defaultCreationOptions); } /// /// Creates a Task that represents a pair of begin /// and end methods that conform to the Asynchronous Programming Model pattern. /// /// The type of the first argument passed to the /// delegate. /// The type of the second argument passed to /// delegate. /// The delegate that begins the asynchronous operation. /// The delegate that ends the asynchronous operation. /// The first argument passed to the /// delegate. /// The second argument passed to the /// delegate. /// The TaskCreationOptions value that controls the behavior of the /// created Task. /// An object containing data to be used by the /// delegate. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// The created Task that represents the /// asynchronous operation. /// /// This method throws any exceptions thrown by the . /// public Task FromAsync( Func beginMethod, Action endMethod, TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(beginMethod, null, endMethod, arg1, arg2, state, creationOptions); } /// /// Creates a Task that represents a pair of begin /// and end methods that conform to the Asynchronous Programming Model pattern. /// /// The type of the first argument passed to the /// delegate. /// The type of the second argument passed to /// delegate. /// The type of the third argument passed to /// delegate. /// The delegate that begins the asynchronous operation. /// The delegate that ends the asynchronous operation. /// The first argument passed to the /// delegate. /// The second argument passed to the /// delegate. /// The third argument passed to the /// delegate. /// An object containing data to be used by the /// delegate. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The created Task that represents the /// asynchronous operation. /// /// This method throws any exceptions thrown by the . /// public Task FromAsync( Func beginMethod, Action endMethod, TArg1 arg1, TArg2 arg2, TArg3 arg3, object state) { return FromAsync(beginMethod, endMethod, arg1, arg2, arg3, state, m_defaultCreationOptions); } /// /// Creates a Task that represents a pair of begin /// and end methods that conform to the Asynchronous Programming Model pattern. /// /// The type of the first argument passed to the /// delegate. /// The type of the second argument passed to /// delegate. /// The type of the third argument passed to /// delegate. /// The delegate that begins the asynchronous operation. /// The delegate that ends the asynchronous operation. /// The first argument passed to the /// delegate. /// The second argument passed to the /// delegate. /// The third argument passed to the /// delegate. /// The TaskCreationOptions value that controls the behavior of the /// created Task. /// An object containing data to be used by the /// delegate. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// The created Task that represents the /// asynchronous operation. /// /// This method throws any exceptions thrown by the . /// public Task FromAsync( Func beginMethod, Action endMethod, TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(beginMethod, null, endMethod, arg1, arg2, arg3, state, creationOptions); } // // Additional FromAsync() overloads used for inferencing convenience // /// /// Creates a Task that executes an end /// method function when a specified IAsyncResult completes. /// /// The type of the result available through the /// Task. /// /// The IAsyncResult whose completion should trigger the processing of the /// . /// The function delegate that processes the completed . /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// A Task that represents the /// asynchronous operation. public Task FromAsync( IAsyncResult asyncResult, Func endMethod) { return TaskFactory.FromAsyncImpl(asyncResult, endMethod, null, m_defaultCreationOptions, DefaultScheduler); } /// /// Creates a Task that executes an end /// method function when a specified IAsyncResult completes. /// /// The type of the result available through the /// Task. /// /// The IAsyncResult whose completion should trigger the processing of the /// . /// The function delegate that processes the completed . /// The TaskCreationOptions value that controls the behavior of the /// created Task. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// A Task that represents the /// asynchronous operation. public Task FromAsync( IAsyncResult asyncResult, Func endMethod, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(asyncResult, endMethod, null, creationOptions, DefaultScheduler); } /// /// Creates a Task that executes an end /// method function when a specified IAsyncResult completes. /// /// The type of the result available through the /// Task. /// /// The IAsyncResult whose completion should trigger the processing of the /// . /// The function delegate that processes the completed . /// The TaskScheduler /// that is used to schedule the task that executes the end method. /// The TaskCreationOptions value that controls the behavior of the /// created Task. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// A Task that represents the /// asynchronous operation. public Task FromAsync( IAsyncResult asyncResult, Func endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler) { return TaskFactory.FromAsyncImpl(asyncResult, endMethod, null, creationOptions, scheduler); } /// /// Creates a Task that represents a pair of /// begin and end methods that conform to the Asynchronous Programming Model pattern. /// /// The type of the result available through the /// Task. /// /// The delegate that begins the asynchronous operation. /// The delegate that ends the asynchronous operation. /// An object containing data to be used by the /// delegate. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The created Task that /// represents the asynchronous operation. /// /// This method throws any exceptions thrown by the . /// public Task FromAsync( Func beginMethod, Func endMethod, object state) { return TaskFactory.FromAsyncImpl(beginMethod, endMethod, null, state, m_defaultCreationOptions); } /// /// Creates a Task that represents a pair of /// begin and end methods that conform to the Asynchronous Programming Model pattern. /// /// The type of the result available through the /// Task. /// /// The delegate that begins the asynchronous operation. /// The delegate that ends the asynchronous operation. /// The TaskCreationOptions value that controls the behavior of the /// created Task. /// An object containing data to be used by the /// delegate. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// The created Task that /// represents the asynchronous operation. /// /// This method throws any exceptions thrown by the . /// public Task FromAsync( Func beginMethod, Func endMethod, object state, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(beginMethod, endMethod, null, state, creationOptions); } /// /// Creates a Task that represents a pair of /// begin and end methods that conform to the Asynchronous Programming Model pattern. /// /// The type of the first argument passed to the delegate. /// The type of the result available through the /// Task. /// /// The delegate that begins the asynchronous operation. /// The delegate that ends the asynchronous operation. /// The first argument passed to the /// delegate. /// An object containing data to be used by the /// delegate. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The created Task that /// represents the asynchronous operation. /// /// This method throws any exceptions thrown by the . /// public Task FromAsync( Func beginMethod, Func endMethod, TArg1 arg1, object state) { return TaskFactory.FromAsyncImpl(beginMethod, endMethod, null, arg1, state, m_defaultCreationOptions); } /// /// Creates a Task that represents a pair of /// begin and end methods that conform to the Asynchronous Programming Model pattern. /// /// The type of the first argument passed to the delegate. /// The type of the result available through the /// Task. /// /// The delegate that begins the asynchronous operation. /// The delegate that ends the asynchronous operation. /// The first argument passed to the /// delegate. /// The TaskCreationOptions value that controls the behavior of the /// created Task. /// An object containing data to be used by the /// delegate. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// The created Task that /// represents the asynchronous operation. /// /// This method throws any exceptions thrown by the . /// public Task FromAsync(Func beginMethod, Func endMethod, TArg1 arg1, object state, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(beginMethod, endMethod, null, arg1, state, creationOptions); } /// /// Creates a Task that represents a pair of /// begin and end methods that conform to the Asynchronous Programming Model pattern. /// /// The type of the first argument passed to the delegate. /// The type of the second argument passed to /// delegate. /// The type of the result available through the /// Task. /// /// The delegate that begins the asynchronous operation. /// The delegate that ends the asynchronous operation. /// The first argument passed to the /// delegate. /// The second argument passed to the /// delegate. /// An object containing data to be used by the /// delegate. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The created Task that /// represents the asynchronous operation. /// /// This method throws any exceptions thrown by the . /// public Task FromAsync(Func beginMethod, Func endMethod, TArg1 arg1, TArg2 arg2, object state) { return TaskFactory.FromAsyncImpl(beginMethod, endMethod, null, arg1, arg2, state, m_defaultCreationOptions); } /// /// Creates a Task that represents a pair of /// begin and end methods that conform to the Asynchronous Programming Model pattern. /// /// The type of the first argument passed to the delegate. /// The type of the second argument passed to /// delegate. /// The type of the result available through the /// Task. /// /// The delegate that begins the asynchronous operation. /// The delegate that ends the asynchronous operation. /// The first argument passed to the /// delegate. /// The second argument passed to the /// delegate. /// The TaskCreationOptions value that controls the behavior of the /// created Task. /// An object containing data to be used by the /// delegate. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// The created Task that /// represents the asynchronous operation. /// /// This method throws any exceptions thrown by the . /// public Task FromAsync( Func beginMethod, Func endMethod, TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(beginMethod, endMethod, null, arg1, arg2, state, creationOptions); } /// /// Creates a Task that represents a pair of /// begin and end methods that conform to the Asynchronous Programming Model pattern. /// /// The type of the first argument passed to the delegate. /// The type of the second argument passed to /// delegate. /// The type of the third argument passed to /// delegate. /// The type of the result available through the /// Task. /// /// The delegate that begins the asynchronous operation. /// The delegate that ends the asynchronous operation. /// The first argument passed to the /// delegate. /// The second argument passed to the /// delegate. /// The third argument passed to the /// delegate. /// An object containing data to be used by the /// delegate. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The created Task that /// represents the asynchronous operation. /// /// This method throws any exceptions thrown by the . /// public Task FromAsync( Func beginMethod, Func endMethod, TArg1 arg1, TArg2 arg2, TArg3 arg3, object state) { return TaskFactory.FromAsyncImpl(beginMethod, endMethod, null, arg1, arg2, arg3, state, m_defaultCreationOptions); } /// /// Creates a Task that represents a pair of /// begin and end methods that conform to the Asynchronous Programming Model pattern. /// /// The type of the first argument passed to the delegate. /// The type of the second argument passed to /// delegate. /// The type of the third argument passed to /// delegate. /// The type of the result available through the /// Task. /// /// The delegate that begins the asynchronous operation. /// The delegate that ends the asynchronous operation. /// The first argument passed to the /// delegate. /// The second argument passed to the /// delegate. /// The third argument passed to the /// delegate. /// The TaskCreationOptions value that controls the behavior of the /// created Task. /// An object containing data to be used by the /// delegate. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument specifies an invalid TaskCreationOptions /// value. /// The created Task that /// represents the asynchronous operation. /// /// This method throws any exceptions thrown by the . /// public Task FromAsync( Func beginMethod, Func endMethod, TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(beginMethod, endMethod, null, arg1, arg2, arg3, state, creationOptions); } /// /// Check validity of options passed to FromAsync method /// /// The options to be validated. /// determines type of FromAsync method that called this method internal static void CheckFromAsyncOptions(TaskCreationOptions creationOptions, bool hasBeginMethod) { if (hasBeginMethod) { // Options detected here cause exceptions in FromAsync methods that take beginMethod as a parameter if ((creationOptions & TaskCreationOptions.LongRunning) != 0) throw new ArgumentOutOfRangeException(nameof(creationOptions), SR.Task_FromAsync_LongRunning); if ((creationOptions & TaskCreationOptions.PreferFairness) != 0) throw new ArgumentOutOfRangeException(nameof(creationOptions), SR.Task_FromAsync_PreferFairness); } // Check for general validity of options if ((creationOptions & ~(TaskCreationOptions.AttachedToParent | TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler | TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning)) != 0) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.creationOptions); } } // // ContinueWhenAll methods // // A Task that, given an initial collection of N tasks, will complete when // it has been invoked N times. This allows us to replace this logic: // Task promise = new Task(...); // int _count = tasksCopy.Length; // Action completionAction = delegate {if(Interlocked.Decrement(ref _count) == 0) promise.TrySetResult(tasksCopy); // for(int i=0; i<_count; i++) // tasksCopy[i].AddCompletionAction(completionAction); // with this logic: // CompletionOnCountdownPromise promise = new CompletionOnCountdownPromise(tasksCopy); // for(int i=0; i, ITaskCompletionAction { private readonly Task[] _tasks; private int _count; internal CompleteOnCountdownPromise(Task[] tasksCopy) : base() { Debug.Assert((tasksCopy != null) && (tasksCopy.Length > 0), "Expected non-null task array with at least one element in it"); _tasks = tasksCopy; _count = tasksCopy.Length; if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationCreation(this, "TaskFactory.ContinueWhenAll"); if (Task.s_asyncDebuggingEnabled) AddToActiveTasks(this); } public void Invoke(Task completingTask) { if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationRelation(this, CausalityRelation.Join); if (completingTask.IsWaitNotificationEnabled) this.SetNotificationForWaitCompletion(enabled: true); if (Interlocked.Decrement(ref _count) == 0) { if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationCompletion(this, AsyncCausalityStatus.Completed); if (Task.s_asyncDebuggingEnabled) RemoveFromActiveTasks(this); TrySetResult(_tasks); } Debug.Assert(_count >= 0, "Count should never go below 0"); } public bool InvokeMayRunArbitraryCode { get { return true; } } /// /// Returns whether we should notify the debugger of a wait completion. This returns /// true iff at least one constituent task has its bit set. /// internal override bool ShouldNotifyDebuggerOfWaitCompletion { get { return base.ShouldNotifyDebuggerOfWaitCompletion && Task.AnyTaskRequiresNotifyDebuggerOfWaitCompletion(_tasks); } } } // Performs some logic common to all ContinueWhenAll() overloads internal static Task CommonCWAllLogic(Task[] tasksCopy) { Debug.Assert(tasksCopy != null); // Create a promise task to be returned to the user CompleteOnCountdownPromise promise = new CompleteOnCountdownPromise(tasksCopy); for (int i = 0; i < tasksCopy.Length; i++) { if (tasksCopy[i].IsCompleted) promise.Invoke(tasksCopy[i]); // Short-circuit the completion action, if possible else tasksCopy[i].AddCompletionAction(promise); // simple completion action } return promise; } // A Task[]> that, given an initial collection of N tasks, will complete when // it has been invoked N times. See comments for non-generic CompleteOnCountdownPromise class. // // Used in TaskFactory.CommonCWAllLogic(Task[]), below. private sealed class CompleteOnCountdownPromise : Task[]>, ITaskCompletionAction { private readonly Task[] _tasks; private int _count; internal CompleteOnCountdownPromise(Task[] tasksCopy) : base() { Debug.Assert((tasksCopy != null) && (tasksCopy.Length > 0), "Expected non-null task array with at least one element in it"); _tasks = tasksCopy; _count = tasksCopy.Length; if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationCreation(this, "TaskFactory.ContinueWhenAll<>"); if (Task.s_asyncDebuggingEnabled) AddToActiveTasks(this); } public void Invoke(Task completingTask) { if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationRelation(this, CausalityRelation.Join); if (completingTask.IsWaitNotificationEnabled) this.SetNotificationForWaitCompletion(enabled: true); if (Interlocked.Decrement(ref _count) == 0) { if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationCompletion(this, AsyncCausalityStatus.Completed); if (Task.s_asyncDebuggingEnabled) RemoveFromActiveTasks(this); TrySetResult(_tasks); } Debug.Assert(_count >= 0, "Count should never go below 0"); } public bool InvokeMayRunArbitraryCode { get { return true; } } /// /// Returns whether we should notify the debugger of a wait completion. This returns /// true iff at least one constituent task has its bit set. /// internal override bool ShouldNotifyDebuggerOfWaitCompletion { get { return base.ShouldNotifyDebuggerOfWaitCompletion && Task.AnyTaskRequiresNotifyDebuggerOfWaitCompletion(_tasks); } } } internal static Task[]> CommonCWAllLogic(Task[] tasksCopy) { Debug.Assert(tasksCopy != null); // Create a promise task to be returned to the user CompleteOnCountdownPromise promise = new CompleteOnCountdownPromise(tasksCopy); for (int i = 0; i < tasksCopy.Length; i++) { if (tasksCopy[i].IsCompleted) promise.Invoke(tasksCopy[i]); // Short-circuit the completion action, if possible else tasksCopy[i].AddCompletionAction(promise); // simple completion action } return promise; } /// /// Creates a continuation Task /// that will be started upon the completion of a set of provided Tasks. /// /// The array of tasks from which to continue. /// The action delegate to execute when all tasks in /// the array have completed. /// The new continuation Task. /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. public Task ContinueWhenAll(Task[] tasks, Action continuationAction) { if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction)); return TaskFactory.ContinueWhenAllImpl(tasks, null, continuationAction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of a set of provided Tasks. /// /// The array of tasks from which to continue. /// The action delegate to execute when all tasks in /// the array have completed. /// The CancellationToken /// that will be assigned to the new continuation task. /// The new continuation Task. /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The provided CancellationToken /// has already been disposed. /// public Task ContinueWhenAll(Task[] tasks, Action continuationAction, CancellationToken cancellationToken) { if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction)); return TaskFactory.ContinueWhenAllImpl(tasks, null, continuationAction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of a set of provided Tasks. /// /// The array of tasks from which to continue. /// The action delegate to execute when all tasks in the array have completed. /// The /// TaskContinuationOptions value that controls the behavior of /// the created continuation Task. /// The new continuation Task. /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The exception that is thrown when the /// argument specifies an invalid TaskContinuationOptions /// value. /// /// The NotOn* and OnlyOn* TaskContinuationOptions, /// which constrain for which TaskStatus states a continuation /// will be executed, are illegal with ContinueWhenAll. /// public Task ContinueWhenAll(Task[] tasks, Action continuationAction, TaskContinuationOptions continuationOptions) { if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction)); return TaskFactory.ContinueWhenAllImpl(tasks, null, continuationAction, continuationOptions, m_defaultCancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of a set of provided Tasks. /// /// The array of tasks from which to continue. /// The action delegate to execute when all tasks in the array have completed. /// The CancellationToken /// that will be assigned to the new continuation task. /// The /// TaskContinuationOptions value that controls the behavior of /// the created continuation Task. /// The TaskScheduler /// that is used to schedule the created continuation Task. /// The new continuation Task. /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The exception that is thrown when the /// argument specifies an invalid TaskContinuationOptions /// value. /// The provided CancellationToken /// has already been disposed. /// /// /// The NotOn* and OnlyOn* TaskContinuationOptions, /// which constrain for which TaskStatus states a continuation /// will be executed, are illegal with ContinueWhenAll. /// public Task ContinueWhenAll(Task[] tasks, Action continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction)); return TaskFactory.ContinueWhenAllImpl(tasks, null, continuationAction, continuationOptions, cancellationToken, scheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of a set of provided Tasks. /// /// The type of the result of the antecedent . /// The array of tasks from which to continue. /// The action delegate to execute when all tasks in /// the array have completed. /// The new continuation Task. /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. public Task ContinueWhenAll(Task[] tasks, Action[]> continuationAction) { if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction)); return TaskFactory.ContinueWhenAllImpl(tasks, null, continuationAction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of a set of provided Tasks. /// /// The type of the result of the antecedent . /// The array of tasks from which to continue. /// The action delegate to execute when all tasks in /// the array have completed. /// The CancellationToken /// that will be assigned to the new continuation task. /// The new continuation Task. /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The provided CancellationToken /// has already been disposed. /// public Task ContinueWhenAll(Task[] tasks, Action[]> continuationAction, CancellationToken cancellationToken) { if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction)); return TaskFactory.ContinueWhenAllImpl(tasks, null, continuationAction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of a set of provided Tasks. /// /// The type of the result of the antecedent . /// The array of tasks from which to continue. /// The action delegate to execute when all tasks in the array have completed. /// The /// TaskContinuationOptions value that controls the behavior of /// the created continuation Task. /// The new continuation Task. /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The exception that is thrown when the /// argument specifies an invalid TaskContinuationOptions /// value. /// /// The NotOn* and OnlyOn* TaskContinuationOptions, /// which constrain for which TaskStatus states a continuation /// will be executed, are illegal with ContinueWhenAll. /// public Task ContinueWhenAll(Task[] tasks, Action[]> continuationAction, TaskContinuationOptions continuationOptions) { if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction)); return TaskFactory.ContinueWhenAllImpl(tasks, null, continuationAction, continuationOptions, m_defaultCancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of a set of provided Tasks. /// /// The type of the result of the antecedent . /// The array of tasks from which to continue. /// The action delegate to execute when all tasks in the array have completed. /// The CancellationToken /// that will be assigned to the new continuation task. /// The /// TaskContinuationOptions value that controls the behavior of /// the created continuation Task. /// The TaskScheduler /// that is used to schedule the created continuation Task. /// The new continuation Task. /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The exception that is thrown when the /// argument specifies an invalid TaskContinuationOptions /// value. /// The provided CancellationToken /// has already been disposed. /// /// /// The NotOn* and OnlyOn* TaskContinuationOptions, /// which constrain for which TaskStatus states a continuation /// will be executed, are illegal with ContinueWhenAll. /// public Task ContinueWhenAll(Task[] tasks, Action[]> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction)); return TaskFactory.ContinueWhenAllImpl(tasks, null, continuationAction, continuationOptions, cancellationToken, scheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of a set of provided Tasks. /// /// The type of the result that is returned by the /// delegate and associated with the created . /// The array of tasks from which to continue. /// The function delegate to execute when all tasks in the /// array have completed. /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. public Task ContinueWhenAll(Task[] tasks, Func continuationFunction) { if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction)); return TaskFactory.ContinueWhenAllImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of a set of provided Tasks. /// /// The type of the result that is returned by the /// delegate and associated with the created . /// The array of tasks from which to continue. /// The function delegate to execute when all tasks in the /// array have completed. /// The CancellationToken /// that will be assigned to the new continuation task. /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The provided CancellationToken /// has already been disposed. /// public Task ContinueWhenAll(Task[] tasks, Func continuationFunction, CancellationToken cancellationToken) { if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction)); return TaskFactory.ContinueWhenAllImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of a set of provided Tasks. /// /// The type of the result that is returned by the /// delegate and associated with the created . /// The array of tasks from which to continue. /// The function delegate to execute when all tasks in the /// array have completed. /// The /// TaskContinuationOptions value that controls the behavior of /// the created continuation Task. /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The exception that is thrown when the /// argument specifies an invalid TaskContinuationOptions /// value. /// /// The NotOn* and OnlyOn* TaskContinuationOptions, /// which constrain for which TaskStatus states a continuation /// will be executed, are illegal with ContinueWhenAll. /// public Task ContinueWhenAll(Task[] tasks, Func continuationFunction, TaskContinuationOptions continuationOptions) { if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction)); return TaskFactory.ContinueWhenAllImpl(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of a set of provided Tasks. /// /// The type of the result that is returned by the /// delegate and associated with the created . /// The array of tasks from which to continue. /// The function delegate to execute when all tasks in the /// array have completed. /// The CancellationToken /// that will be assigned to the new continuation task. /// The /// TaskContinuationOptions value that controls the behavior of /// the created continuation Task. /// The TaskScheduler /// that is used to schedule the created continuation . /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The exception that is thrown when the /// argument specifies an invalid TaskContinuationOptions /// value. /// The provided CancellationToken /// has already been disposed. /// /// /// The NotOn* and OnlyOn* TaskContinuationOptions, /// which constrain for which TaskStatus states a continuation /// will be executed, are illegal with ContinueWhenAll. /// public Task ContinueWhenAll(Task[] tasks, Func continuationFunction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction)); return TaskFactory.ContinueWhenAllImpl(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of a set of provided Tasks. /// /// The type of the result that is returned by the /// delegate and associated with the created . /// The type of the result of the antecedent . /// The array of tasks from which to continue. /// The function delegate to execute when all tasks in the /// array have completed. /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. public Task ContinueWhenAll(Task[] tasks, Func[], TResult> continuationFunction) { if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction)); return TaskFactory.ContinueWhenAllImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of a set of provided Tasks. /// /// The type of the result that is returned by the /// delegate and associated with the created . /// The type of the result of the antecedent . /// The array of tasks from which to continue. /// The function delegate to execute when all tasks in the /// array have completed. /// The CancellationToken /// that will be assigned to the new continuation task. /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The provided CancellationToken /// has already been disposed. /// public Task ContinueWhenAll(Task[] tasks, Func[], TResult> continuationFunction, CancellationToken cancellationToken) { if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction)); return TaskFactory.ContinueWhenAllImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of a set of provided Tasks. /// /// The type of the result that is returned by the /// delegate and associated with the created . /// The type of the result of the antecedent . /// The array of tasks from which to continue. /// The function delegate to execute when all tasks in the /// array have completed. /// The /// TaskContinuationOptions value that controls the behavior of /// the created continuation Task. /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The exception that is thrown when the /// argument specifies an invalid TaskContinuationOptions /// value. /// /// The NotOn* and OnlyOn* TaskContinuationOptions, /// which constrain for which TaskStatus states a continuation /// will be executed, are illegal with ContinueWhenAll. /// public Task ContinueWhenAll(Task[] tasks, Func[], TResult> continuationFunction, TaskContinuationOptions continuationOptions) { if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction)); return TaskFactory.ContinueWhenAllImpl(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of a set of provided Tasks. /// /// The type of the result that is returned by the /// delegate and associated with the created . /// The type of the result of the antecedent . /// The array of tasks from which to continue. /// The function delegate to execute when all tasks in the /// array have completed. /// The CancellationToken /// that will be assigned to the new continuation task. /// The /// TaskContinuationOptions value that controls the behavior of /// the created continuation Task. /// The TaskScheduler /// that is used to schedule the created continuation . /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The exception that is thrown when the /// argument specifies an invalid TaskContinuationOptions /// value. /// The provided CancellationToken /// has already been disposed. /// /// /// The NotOn* and OnlyOn* TaskContinuationOptions, /// which constrain for which TaskStatus states a continuation /// will be executed, are illegal with ContinueWhenAll. /// public Task ContinueWhenAll(Task[] tasks, Func[], TResult> continuationFunction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction)); return TaskFactory.ContinueWhenAllImpl(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler); } // // ContinueWhenAny methods // // A Task that will be completed the first time that Invoke is called. // It allows us to replace this logic: // Task promise = new Task(...); // Action completionAction = delegate(Task completingTask) { promise.TrySetResult(completingTask); } // for(int i=0; i, ITaskCompletionAction { private IList _tasks; // must track this for cleanup private int m_firstTaskAlreadyCompleted; public CompleteOnInvokePromise(IList tasks) : base() { Debug.Assert(tasks != null, "Expected non-null collection of tasks"); _tasks = tasks; if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationCreation(this, "TaskFactory.ContinueWhenAny"); if (Task.s_asyncDebuggingEnabled) AddToActiveTasks(this); } public void Invoke(Task completingTask) { if (m_firstTaskAlreadyCompleted == 0 && Interlocked.Exchange(ref m_firstTaskAlreadyCompleted, 1) == 0) { if (AsyncCausalityTracer.LoggingOn) { AsyncCausalityTracer.TraceOperationRelation(this, CausalityRelation.Choice); AsyncCausalityTracer.TraceOperationCompletion(this, AsyncCausalityStatus.Completed); } if (Task.s_asyncDebuggingEnabled) RemoveFromActiveTasks(this); bool success = TrySetResult(completingTask); Debug.Assert(success, "Only one task should have gotten to this point, and thus this must be successful."); // We need to remove continuations that may be left straggling on other tasks. // Otherwise, repeated calls to WhenAny using the same task could leak actions. // This may also help to avoided unnecessary invocations of this whenComplete delegate. // Note that we may be attempting to remove a continuation from a task that hasn't had it // added yet; while there's overhead there, the operation won't hurt anything. var tasks = _tasks; int numTasks = tasks.Count; for (int i = 0; i < numTasks; i++) { var task = tasks[i]; if (task != null && // if an element was erroneously nulled out concurrently, just skip it; worst case is we don't remove a continuation !task.IsCompleted) task.RemoveContinuation(this); } _tasks = null; } } public bool InvokeMayRunArbitraryCode { get { return true; } } } // Common ContinueWhenAny logic // If the tasks list is not an array, it must be an internal defensive copy so that // we don't need to be concerned about concurrent modifications to the list. If the task list // is an array, it should be a defensive copy if this functionality is being used // asynchronously (e.g. WhenAny) rather than synchronously (e.g. WaitAny). internal static Task CommonCWAnyLogic(IList tasks) { Debug.Assert(tasks != null); // Create a promise task to be returned to the user. // (If this logic ever changes, also update CommonCWAnyLogicCleanup.) var promise = new CompleteOnInvokePromise(tasks); // At the completion of any of the tasks, complete the promise. bool checkArgsOnly = false; int numTasks = tasks.Count; for (int i = 0; i < numTasks; i++) { var task = tasks[i]; if (task == null) throw new ArgumentException(SR.Task_MultiTaskContinuation_NullTask, nameof(tasks)); if (checkArgsOnly) continue; // If the promise has already completed, don't bother with checking any more tasks. if (promise.IsCompleted) { checkArgsOnly = true; } // If a task has already completed, complete the promise. else if (task.IsCompleted) { promise.Invoke(task); checkArgsOnly = true; } // Otherwise, add the completion action and keep going. else { task.AddCompletionAction(promise); if (promise.IsCompleted) { // One of the previous tasks that already had its continuation registered may have // raced to complete with our adding the continuation to this task. The completion // routine would have gone through and removed the continuation from all of the tasks // with which it was already registered, but if the race causes this continuation to // be added after that, it'll never be removed. As such, after adding the continuation, // we check to see whether the promise has already completed, and if it has, we try to // manually remove the continuation from this task. If it was already removed, it'll be // a nop, and if we race to remove it, the synchronization in RemoveContinuation will // keep things consistent. task.RemoveContinuation(promise); } } } return promise; } /// /// Cleans up the operations performed by CommonCWAnyLogic in a case where /// the created continuation task is being discarded. /// /// The task returned from CommonCWAnyLogic. internal static void CommonCWAnyLogicCleanup(Task continuation) { // Force cleanup of the promise (e.g. removing continuations from each // constituent task), by completing the promise with any value. ((CompleteOnInvokePromise)continuation).Invoke(null); } /// /// Creates a continuation Task /// that will be started upon the completion of any Task in the provided set. /// /// The array of tasks from which to continue when one task completes. /// The action delegate to execute when one task in the array completes. /// The new continuation Task. /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. public Task ContinueWhenAny(Task[] tasks, Action continuationAction) { if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction)); return TaskFactory.ContinueWhenAnyImpl(tasks, null, continuationAction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of any Task in the provided set. /// /// The array of tasks from which to continue when one task completes. /// The action delegate to execute when one task in the array completes. /// The CancellationToken /// that will be assigned to the new continuation task. /// The new continuation Task. /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The provided CancellationToken /// has already been disposed. /// public Task ContinueWhenAny(Task[] tasks, Action continuationAction, CancellationToken cancellationToken) { if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction)); return TaskFactory.ContinueWhenAnyImpl(tasks, null, continuationAction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of any Task in the provided set. /// /// The array of tasks from which to continue when one task completes. /// The action delegate to execute when one task in the array completes. /// The /// TaskContinuationOptions value that controls the behavior of /// the created continuation Task. /// The new continuation Task. /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The exception that is thrown when the /// argument specifies an invalid TaskContinuationOptions /// value. /// /// The NotOn* and OnlyOn* TaskContinuationOptions, /// which constrain for which TaskStatus states a continuation /// will be executed, are illegal with ContinueWhenAny. /// public Task ContinueWhenAny(Task[] tasks, Action continuationAction, TaskContinuationOptions continuationOptions) { if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction)); return TaskFactory.ContinueWhenAnyImpl(tasks, null, continuationAction, continuationOptions, m_defaultCancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of any Task in the provided set. /// /// The array of tasks from which to continue when one task completes. /// The action delegate to execute when one task in the array completes. /// The CancellationToken /// that will be assigned to the new continuation task. /// The /// TaskContinuationOptions value that controls the behavior of /// the created continuation Task. /// The TaskScheduler /// that is used to schedule the created continuation Task. /// The new continuation Task. /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The exception that is thrown when the /// argument specifies an invalid TaskContinuationOptions /// value. /// The provided CancellationToken /// has already been disposed. /// /// /// The NotOn* and OnlyOn* TaskContinuationOptions, /// which constrain for which TaskStatus states a continuation /// will be executed, are illegal with ContinueWhenAny. /// public Task ContinueWhenAny(Task[] tasks, Action continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction)); return TaskFactory.ContinueWhenAnyImpl(tasks, null, continuationAction, continuationOptions, cancellationToken, scheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of any Task in the provided set. /// /// The type of the result that is returned by the /// delegate and associated with the created . /// The array of tasks from which to continue when one task completes. /// The function delegate to execute when one task in the /// array completes. /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. public Task ContinueWhenAny(Task[] tasks, Func continuationFunction) { if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction)); return TaskFactory.ContinueWhenAnyImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of any Task in the provided set. /// /// The type of the result that is returned by the /// delegate and associated with the created . /// The array of tasks from which to continue when one task completes. /// The function delegate to execute when one task in the /// array completes. /// The CancellationToken /// that will be assigned to the new continuation task. /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The provided CancellationToken /// has already been disposed. /// public Task ContinueWhenAny(Task[] tasks, Func continuationFunction, CancellationToken cancellationToken) { if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction)); return TaskFactory.ContinueWhenAnyImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of any Task in the provided set. /// /// The type of the result that is returned by the /// delegate and associated with the created . /// The array of tasks from which to continue when one task completes. /// The function delegate to execute when one task in the /// array completes. /// The /// TaskContinuationOptions value that controls the behavior of /// the created continuation Task. /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The exception that is thrown when the /// argument specifies an invalid TaskContinuationOptions /// value. /// /// The NotOn* and OnlyOn* TaskContinuationOptions, /// which constrain for which TaskStatus states a continuation /// will be executed, are illegal with ContinueWhenAny. /// public Task ContinueWhenAny(Task[] tasks, Func continuationFunction, TaskContinuationOptions continuationOptions) { if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction)); return TaskFactory.ContinueWhenAnyImpl(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of any Task in the provided set. /// /// The type of the result that is returned by the /// delegate and associated with the created . /// The array of tasks from which to continue when one task completes. /// The function delegate to execute when one task in the /// array completes. /// The CancellationToken /// that will be assigned to the new continuation task. /// The /// TaskContinuationOptions value that controls the behavior of /// the created continuation Task. /// The TaskScheduler /// that is used to schedule the created continuation . /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The exception that is thrown when the /// argument specifies an invalid TaskContinuationOptions /// value. /// The provided CancellationToken /// has already been disposed. /// /// /// The NotOn* and OnlyOn* TaskContinuationOptions, /// which constrain for which TaskStatus states a continuation /// will be executed, are illegal with ContinueWhenAny. /// public Task ContinueWhenAny(Task[] tasks, Func continuationFunction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction)); return TaskFactory.ContinueWhenAnyImpl(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of any Task in the provided set. /// /// The type of the result that is returned by the /// delegate and associated with the created . /// The type of the result of the antecedent . /// The array of tasks from which to continue when one task completes. /// The function delegate to execute when one task in the /// array completes. /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. public Task ContinueWhenAny(Task[] tasks, Func, TResult> continuationFunction) { if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction)); return TaskFactory.ContinueWhenAnyImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of any Task in the provided set. /// /// The type of the result that is returned by the /// delegate and associated with the created . /// The type of the result of the antecedent . /// The array of tasks from which to continue when one task completes. /// The function delegate to execute when one task in the /// array completes. /// The CancellationToken /// that will be assigned to the new continuation task. /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The provided CancellationToken /// has already been disposed. /// public Task ContinueWhenAny(Task[] tasks, Func, TResult> continuationFunction, CancellationToken cancellationToken) { if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction)); return TaskFactory.ContinueWhenAnyImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of any Task in the provided set. /// /// The type of the result that is returned by the /// delegate and associated with the created . /// The type of the result of the antecedent . /// The array of tasks from which to continue when one task completes. /// The function delegate to execute when one task in the /// array completes. /// The /// TaskContinuationOptions value that controls the behavior of /// the created continuation Task. /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The exception that is thrown when the /// argument specifies an invalid TaskContinuationOptions /// value. /// /// The NotOn* and OnlyOn* TaskContinuationOptions, /// which constrain for which TaskStatus states a continuation /// will be executed, are illegal with ContinueWhenAny. /// public Task ContinueWhenAny(Task[] tasks, Func, TResult> continuationFunction, TaskContinuationOptions continuationOptions) { if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction)); return TaskFactory.ContinueWhenAnyImpl(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of any Task in the provided set. /// /// The type of the result that is returned by the /// delegate and associated with the created . /// The type of the result of the antecedent . /// The array of tasks from which to continue when one task completes. /// The function delegate to execute when one task in the /// array completes. /// The CancellationToken /// that will be assigned to the new continuation task. /// The /// TaskContinuationOptions value that controls the behavior of /// the created continuation Task. /// The TaskScheduler /// that is used to schedule the created continuation . /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The exception that is thrown when the /// argument specifies an invalid TaskContinuationOptions /// value. /// The provided CancellationToken /// has already been disposed. /// /// /// The NotOn* and OnlyOn* TaskContinuationOptions, /// which constrain for which TaskStatus states a continuation /// will be executed, are illegal with ContinueWhenAny. /// public Task ContinueWhenAny(Task[] tasks, Func, TResult> continuationFunction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction)); return TaskFactory.ContinueWhenAnyImpl(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of any Task in the provided set. /// /// The type of the result of the antecedent . /// The array of tasks from which to continue when one task completes. /// The action delegate to execute when one task in the /// array completes. /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. public Task ContinueWhenAny(Task[] tasks, Action> continuationAction) { if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction)); return TaskFactory.ContinueWhenAnyImpl(tasks, null, continuationAction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of any Task in the provided set. /// /// The type of the result of the antecedent . /// The array of tasks from which to continue when one task completes. /// The action delegate to execute when one task in the /// array completes. /// The CancellationToken /// that will be assigned to the new continuation task. /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The provided CancellationToken /// has already been disposed. /// public Task ContinueWhenAny(Task[] tasks, Action> continuationAction, CancellationToken cancellationToken) { if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction)); return TaskFactory.ContinueWhenAnyImpl(tasks, null, continuationAction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of any Task in the provided set. /// /// The type of the result of the antecedent . /// The array of tasks from which to continue when one task completes. /// The action delegate to execute when one task in the /// array completes. /// The /// TaskContinuationOptions value that controls the behavior of /// the created continuation Task. /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The exception that is thrown when the /// argument specifies an invalid TaskContinuationOptions /// value. /// /// The NotOn* and OnlyOn* TaskContinuationOptions, /// which constrain for which TaskStatus states a continuation /// will be executed, are illegal with ContinueWhenAny. /// public Task ContinueWhenAny(Task[] tasks, Action> continuationAction, TaskContinuationOptions continuationOptions) { if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction)); return TaskFactory.ContinueWhenAnyImpl(tasks, null, continuationAction, continuationOptions, m_defaultCancellationToken, DefaultScheduler); } /// /// Creates a continuation Task /// that will be started upon the completion of any Task in the provided set. /// /// The type of the result of the antecedent . /// The array of tasks from which to continue when one task completes. /// The action delegate to execute when one task in the /// array completes. /// The CancellationToken /// that will be assigned to the new continuation task. /// The /// TaskContinuationOptions value that controls the behavior of /// the created continuation Task. /// The TaskScheduler /// that is used to schedule the created continuation . /// The new continuation . /// The exception that is thrown when the /// array is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// argument is null. /// The exception that is thrown when the /// array contains a null value. /// The exception that is thrown when the /// array is empty. /// The exception that is thrown when the /// argument specifies an invalid TaskContinuationOptions /// value. /// The provided CancellationToken /// has already been disposed. /// /// /// The NotOn* and OnlyOn* TaskContinuationOptions, /// which constrain for which TaskStatus states a continuation /// will be executed, are illegal with ContinueWhenAny. /// public Task ContinueWhenAny(Task[] tasks, Action> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction)); return TaskFactory.ContinueWhenAnyImpl(tasks, null, continuationAction, continuationOptions, cancellationToken, scheduler); } // Check task array and return a defensive copy. // Used with ContinueWhenAll()/ContinueWhenAny(). internal static Task[] CheckMultiContinuationTasksAndCopy(Task[] tasks) { if (tasks == null) throw new ArgumentNullException(nameof(tasks)); if (tasks.Length == 0) throw new ArgumentException(SR.Task_MultiTaskContinuation_EmptyTaskList, nameof(tasks)); Task[] tasksCopy = new Task[tasks.Length]; for (int i = 0; i < tasks.Length; i++) { tasksCopy[i] = tasks[i]; if (tasksCopy[i] == null) throw new ArgumentException(SR.Task_MultiTaskContinuation_NullTask, nameof(tasks)); } return tasksCopy; } internal static Task[] CheckMultiContinuationTasksAndCopy(Task[] tasks) { if (tasks == null) throw new ArgumentNullException(nameof(tasks)); if (tasks.Length == 0) throw new ArgumentException(SR.Task_MultiTaskContinuation_EmptyTaskList, nameof(tasks)); Task[] tasksCopy = new Task[tasks.Length]; for (int i = 0; i < tasks.Length; i++) { tasksCopy[i] = tasks[i]; if (tasksCopy[i] == null) throw new ArgumentException(SR.Task_MultiTaskContinuation_NullTask, nameof(tasks)); } return tasksCopy; } // Throw an exception if "options" argument specifies illegal options internal static void CheckMultiTaskContinuationOptions(TaskContinuationOptions continuationOptions) { // Construct a mask to check for illegal options const TaskContinuationOptions NotOnAny = TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.NotOnRanToCompletion; // Check that LongRunning and ExecuteSynchronously are not specified together const TaskContinuationOptions illegalMask = TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.LongRunning; if ((continuationOptions & illegalMask) == illegalMask) { throw new ArgumentOutOfRangeException(nameof(continuationOptions), SR.Task_ContinueWith_ESandLR); } // Check that no nonsensical options are specified. if ((continuationOptions & ~( TaskContinuationOptions.LongRunning | TaskContinuationOptions.PreferFairness | TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.DenyChildAttach | TaskContinuationOptions.HideScheduler | TaskContinuationOptions.LazyCancellation | NotOnAny | TaskContinuationOptions.ExecuteSynchronously)) != 0) { throw new ArgumentOutOfRangeException(nameof(continuationOptions)); } // Check that no "fire" options are specified. if ((continuationOptions & NotOnAny) != 0) throw new ArgumentOutOfRangeException(nameof(continuationOptions), SR.Task_MultiTaskContinuation_FireOptions); } } }