From fae4bf2c48127c90f80f65497b8910b86c687781 Mon Sep 17 00:00:00 2001 From: Weihan Li Date: Wed, 17 Apr 2024 01:33:32 +0800 Subject: [PATCH] refactor: update TaskCompletionSource implementation --- .../Helpers/TaskCompletionSource.cs | 141 ++---------------- 1 file changed, 11 insertions(+), 130 deletions(-) diff --git a/src/WeihanLi.Common/Helpers/TaskCompletionSource.cs b/src/WeihanLi.Common/Helpers/TaskCompletionSource.cs index f1745356..801478bc 100644 --- a/src/WeihanLi.Common/Helpers/TaskCompletionSource.cs +++ b/src/WeihanLi.Common/Helpers/TaskCompletionSource.cs @@ -29,11 +29,12 @@ namespace System.Threading.Tasks /// public class TaskCompletionSource { - private readonly Task _task; - + private readonly TaskCompletionSource _taskCompletionSource; + /// Creates a . - public TaskCompletionSource() => _task = new Task(); - + public TaskCompletionSource() => _taskCompletionSource = new(); + + /// Creates a with the specified options. /// /// The created by this instance and accessible through its property @@ -62,7 +63,7 @@ public TaskCompletionSource(object? state) : /// The state to use as the underlying 's AsyncState. /// The represent options invalid for use with a . public TaskCompletionSource(object? state, TaskCreationOptions creationOptions) => - _task = new Task(state, creationOptions, promiseStyle: true); + _taskCompletionSource = new(state, creationOptions); /// /// Gets the created @@ -74,7 +75,7 @@ public TaskCompletionSource(object? state, TaskCreationOptions creationOptions) /// and methods (and their "Try" variants) on this instance all result in the relevant state /// transitions on this underlying Task. /// - public Task Task => _task; + public Task Task => _taskCompletionSource.Task; /// Transitions the underlying into the state. /// The exception to bind to this . @@ -125,18 +126,7 @@ public void SetException(IEnumerable exceptions) /// The argument is null. public bool TrySetException(Exception exception) { - if (exception is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception); - } - - bool rval = _task.TrySetException(exception); - if (!rval && !_task.IsCompleted) - { - _task.SpinUntilCompleted(); - } - - return rval; + return _taskCompletionSource.TrySetException(exception); } /// @@ -155,34 +145,7 @@ public bool TrySetException(Exception exception) /// The collection is empty. public bool TrySetException(IEnumerable exceptions) { - if (exceptions is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exceptions); - } - - var defensiveCopy = new List(); - foreach (Exception e in exceptions) - { - if (e is null) - { - ThrowHelper.ThrowArgumentException(ExceptionResource.TaskCompletionSourceT_TrySetException_NullException, ExceptionArgument.exceptions); - } - - defensiveCopy.Add(e); - } - - if (defensiveCopy.Count == 0) - { - ThrowHelper.ThrowArgumentException(ExceptionResource.TaskCompletionSourceT_TrySetException_NoExceptions, ExceptionArgument.exceptions); - } - - bool rval = _task.TrySetException(defensiveCopy); - if (!rval && !_task.IsCompleted) - { - _task.SpinUntilCompleted(); - } - - return rval; + return _taskCompletionSource.TrySetException(exceptions); } /// @@ -214,13 +177,7 @@ public void SetResult() /// public bool TrySetResult() { - bool rval = _task.TrySetResult(); - if (!rval) - { - _task.SpinUntilCompleted(); - } - - return rval; + return _taskCompletionSource.TrySetResult(null); } /// @@ -278,83 +235,7 @@ public void SetCanceled(CancellationToken cancellationToken) /// public bool TrySetCanceled(CancellationToken cancellationToken) { - bool rval = _task.TrySetCanceled(cancellationToken); - if (!rval && !_task.IsCompleted) - { - _task.SpinUntilCompleted(); - } - - return rval; - } - - /// - /// Transition the underlying into the same completion state as the specified . - /// - /// The completed task whose completion status (including exception or cancellation information) should be copied to the underlying task. - /// is . - /// is not completed. - /// - /// The underlying is already in one of the three final states: - /// , , or . - /// - /// - /// This operation will return false if the is already in one of the three final states: - /// , , or . - /// - public void SetFromTask(Task completedTask) - { - if (!TrySetFromTask(completedTask)) - { - ThrowHelper.ThrowInvalidOperationException(ExceptionResource.TaskT_TransitionToFinal_AlreadyCompleted); - } - } - - /// - /// Attempts to transition the underlying into the same completion state as the specified . - /// - /// The completed task whose completion status (including exception or cancellation information) should be copied to the underlying task. - /// if the operation was successful; otherwise, . - /// is . - /// is not completed. - /// - /// This operation will return false if the is already in one of the three final states: - /// , , or . - /// - public bool TrySetFromTask(Task completedTask) - { - ArgumentNullException.ThrowIfNull(completedTask); - if (!completedTask.IsCompleted) - { - throw new ArgumentException(SR.Task_MustBeCompleted, nameof(completedTask)); - } - - // Try to transition to the appropriate final state based on the state of completedTask. - bool result = false; - switch (completedTask.Status) - { - case TaskStatus.RanToCompletion: - result = _task.TrySetResult(); - break; - - case TaskStatus.Canceled: - result = _task.TrySetCanceled(completedTask.CancellationToken, completedTask.GetCancellationExceptionDispatchInfo()); - break; - - case TaskStatus.Faulted: - result = _task.TrySetException(completedTask.GetExceptionDispatchInfos()); - break; - } - - // If we successfully transitioned to a final state, we're done. If we didn't, it's possible a concurrent operation - // is still in the process of completing the task, and callers of this method expect the task to already be fully - // completed when this method returns. As such, we spin until the task is completed, and then return whether this - // call successfully did the transition. - if (!result && !_task.IsCompleted) - { - _task.SpinUntilCompleted(); - } - - return result; + return _taskCompletionSource.TrySetCanceled(cancellationToken); } } }