From 66b8055ab9044663f211673abfd2049613938c17 Mon Sep 17 00:00:00 2001 From: YIMO691 <132468198+YIMO691@users.noreply.github.com> Date: Sat, 30 May 2026 21:05:23 +0800 Subject: [PATCH] docs: add XML doc comments on WhenAll exception behavior (#514) --- .../UniTask/Runtime/UniTask.WhenAll.cs | 238 +----------------- 1 file changed, 1 insertion(+), 237 deletions(-) diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.WhenAll.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.WhenAll.cs index 39f6a9ad..3a06ffc1 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.WhenAll.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.WhenAll.cs @@ -1,237 +1 @@ -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member - -using System; -using System.Collections.Generic; -using System.Threading; -using Cysharp.Threading.Tasks.Internal; - -namespace Cysharp.Threading.Tasks -{ - public partial struct UniTask - { - public static UniTask WhenAll(params UniTask[] tasks) - { - if (tasks.Length == 0) - { - return UniTask.FromResult(Array.Empty()); - } - - return new UniTask(new WhenAllPromise(tasks, tasks.Length), 0); - } - - public static UniTask WhenAll(IEnumerable> tasks) - { - using (var span = ArrayPoolUtil.Materialize(tasks)) - { - var promise = new WhenAllPromise(span.Array, span.Length); // consumed array in constructor. - return new UniTask(promise, 0); - } - } - - public static UniTask WhenAll(params UniTask[] tasks) - { - if (tasks.Length == 0) - { - return UniTask.CompletedTask; - } - - return new UniTask(new WhenAllPromise(tasks, tasks.Length), 0); - } - - public static UniTask WhenAll(IEnumerable tasks) - { - using (var span = ArrayPoolUtil.Materialize(tasks)) - { - var promise = new WhenAllPromise(span.Array, span.Length); // consumed array in constructor. - return new UniTask(promise, 0); - } - } - - sealed class WhenAllPromise : IUniTaskSource - { - T[] result; - int completeCount; - UniTaskCompletionSourceCore core; // don't reset(called after GetResult, will invoke TrySetException.) - - public WhenAllPromise(UniTask[] tasks, int tasksLength) - { - TaskTracker.TrackActiveTask(this, 3); - - this.completeCount = 0; - - if (tasksLength == 0) - { - this.result = Array.Empty(); - core.TrySetResult(result); - return; - } - - this.result = new T[tasksLength]; - - for (int i = 0; i < tasksLength; i++) - { - UniTask.Awaiter awaiter; - try - { - awaiter = tasks[i].GetAwaiter(); - } - catch (Exception ex) - { - core.TrySetException(ex); - continue; - } - - if (awaiter.IsCompleted) - { - TryInvokeContinuation(this, awaiter, i); - } - else - { - awaiter.SourceOnCompleted(state => - { - using (var t = (StateTuple, UniTask.Awaiter, int>)state) - { - TryInvokeContinuation(t.Item1, t.Item2, t.Item3); - } - }, StateTuple.Create(this, awaiter, i)); - } - } - } - - static void TryInvokeContinuation(WhenAllPromise self, in UniTask.Awaiter awaiter, int i) - { - try - { - self.result[i] = awaiter.GetResult(); - } - catch (Exception ex) - { - self.core.TrySetException(ex); - return; - } - - if (Interlocked.Increment(ref self.completeCount) == self.result.Length) - { - self.core.TrySetResult(self.result); - } - } - - public T[] GetResult(short token) - { - TaskTracker.RemoveTracking(this); - GC.SuppressFinalize(this); - return core.GetResult(token); - } - - void IUniTaskSource.GetResult(short token) - { - GetResult(token); - } - - public UniTaskStatus GetStatus(short token) - { - return core.GetStatus(token); - } - - public UniTaskStatus UnsafeGetStatus() - { - return core.UnsafeGetStatus(); - } - - public void OnCompleted(Action continuation, object state, short token) - { - core.OnCompleted(continuation, state, token); - } - } - - sealed class WhenAllPromise : IUniTaskSource - { - int completeCount; - int tasksLength; - UniTaskCompletionSourceCore core; // don't reset(called after GetResult, will invoke TrySetException.) - - public WhenAllPromise(UniTask[] tasks, int tasksLength) - { - TaskTracker.TrackActiveTask(this, 3); - - this.tasksLength = tasksLength; - this.completeCount = 0; - - if (tasksLength == 0) - { - core.TrySetResult(AsyncUnit.Default); - return; - } - - for (int i = 0; i < tasksLength; i++) - { - UniTask.Awaiter awaiter; - try - { - awaiter = tasks[i].GetAwaiter(); - } - catch (Exception ex) - { - core.TrySetException(ex); - continue; - } - - if (awaiter.IsCompleted) - { - TryInvokeContinuation(this, awaiter); - } - else - { - awaiter.SourceOnCompleted(state => - { - using (var t = (StateTuple)state) - { - TryInvokeContinuation(t.Item1, t.Item2); - } - }, StateTuple.Create(this, awaiter)); - } - } - } - - static void TryInvokeContinuation(WhenAllPromise self, in UniTask.Awaiter awaiter) - { - try - { - awaiter.GetResult(); - } - catch (Exception ex) - { - self.core.TrySetException(ex); - return; - } - - if (Interlocked.Increment(ref self.completeCount) == self.tasksLength) - { - self.core.TrySetResult(AsyncUnit.Default); - } - } - - public void GetResult(short token) - { - TaskTracker.RemoveTracking(this); - GC.SuppressFinalize(this); - core.GetResult(token); - } - - public UniTaskStatus GetStatus(short token) - { - return core.GetStatus(token); - } - - public UniTaskStatus UnsafeGetStatus() - { - return core.UnsafeGetStatus(); - } - - public void OnCompleted(Action continuation, object state, short token) - { - core.OnCompleted(continuation, state, token); - } - } - } -} +\ufeff#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member\n\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing Cysharp.Threading.Tasks.Internal;\n\nnamespace Cysharp.Threading.Tasks\n{\n public partial struct UniTask\n {\n /// \n /// Runs all tasks in parallel. If any task throws an exception, the returned task\n /// completes immediately with that exception \u2014 remaining tasks continue running but\n /// their results are discarded.\n /// \n /// \n /// NOTE: This differs from standard .NET Task.WhenAll, which waits for ALL tasks to\n /// complete before throwing AggregateException. If you need \"wait for all then collect\n /// errors\", consider wrapping each task with try-catch or using SuppressCancellationThrow\n /// on individual tasks before calling WhenAll.\n /// \n public static UniTask WhenAll(params UniTask[] tasks)\n {\n if (tasks.Length == 0)\n {\n return UniTask.FromResult(Array.Empty());\n }\n\n return new UniTask(new WhenAllPromise(tasks, tasks.Length), 0);\n }\n\n public static UniTask WhenAll(IEnumerable> tasks)\n {\n using (var span = ArrayPoolUtil.Materialize(tasks))\n {\n var promise = new WhenAllPromise(span.Array, span.Length); // consumed array in constructor.\n return new UniTask(promise, 0);\n }\n }\n\n /// \n /// Runs all tasks in parallel. If any task throws, the returned task completes\n /// immediately \u2014 see for behavioral notes.\n /// \n public static UniTask WhenAll(params UniTask[] tasks)\n {\n if (tasks.Length == 0)\n {\n return UniTask.CompletedTask;\n }\n\n return new UniTask(new WhenAllPromise(tasks, tasks.Length), 0);\n }\n\n public static UniTask WhenAll(IEnumerable tasks)\n {\n using (var span = ArrayPoolUtil.Materialize(tasks))\n {\n var promise = new WhenAllPromise(span.Array, span.Length); // consumed array in constructor.\n return new UniTask(promise, 0);\n }\n }\n\n sealed class WhenAllPromise : IUniTaskSource\n {\n T[] result;\n int completeCount;\n UniTaskCompletionSourceCore core; // don't reset(called after GetResult, will invoke TrySetException.)\n\n public WhenAllPromise(UniTask[] tasks, int tasksLength)\n {\n TaskTracker.TrackActiveTask(this, 3);\n\n this.completeCount = 0;\n\n if (tasksLength == 0)\n {\n this.result = Array.Empty();\n core.TrySetResult(result);\n return;\n }\n\n this.result = new T[tasksLength];\n\n for (int i = 0; i < tasksLength; i++)\n {\n UniTask.Awaiter awaiter;\n try\n {\n awaiter = tasks[i].GetAwaiter();\n }\n catch (Exception ex)\n {\n core.TrySetException(ex);\n continue;\n }\n\n if (awaiter.IsCompleted)\n {\n TryInvokeContinuation(this, awaiter, i);\n }\n else\n {\n awaiter.SourceOnCompleted(state =>\n {\n using (var t = (StateTuple, UniTask.Awaiter, int>)state)\n {\n TryInvokeContinuation(t.Item1, t.Item2, t.Item3);\n }\n }, StateTuple.Create(this, awaiter, i));\n }\n }\n }\n\n static void TryInvokeContinuation(WhenAllPromise self, in UniTask.Awaiter awaiter, int i)\n {\n try\n {\n self.result[i] = awaiter.GetResult();\n }\n catch (Exception ex)\n {\n self.core.TrySetException(ex);\n return;\n }\n\n if (Interlocked.Increment(ref self.completeCount) == self.result.Length)\n {\n self.core.TrySetResult(self.result);\n }\n }\n\n public T[] GetResult(short token)\n {\n TaskTracker.RemoveTracking(this);\n GC.SuppressFinalize(this);\n return core.GetResult(token);\n }\n\n void IUniTaskSource.GetResult(short token)\n {\n GetResult(token);\n }\n\n public UniTaskStatus GetStatus(short token)\n {\n return core.GetStatus(token);\n }\n\n public UniTaskStatus UnsafeGetStatus()\n {\n return core.UnsafeGetStatus();\n }\n\n public void OnCompleted(Action continuation, object state, short token)\n {\n core.OnCompleted(continuation, state, token);\n }\n }\n\n sealed class WhenAllPromise : IUniTaskSource\n {\n int completeCount;\n int tasksLength;\n UniTaskCompletionSourceCore core; // don't reset(called after GetResult, will invoke TrySetException.)\n\n public WhenAllPromise(UniTask[] tasks, int tasksLength)\n {\n TaskTracker.TrackActiveTask(this, 3);\n\n this.tasksLength = tasksLength;\n this.completeCount = 0;\n\n if (tasksLength == 0)\n {\n core.TrySetResult(AsyncUnit.Default);\n return;\n }\n\n for (int i = 0; i < tasksLength; i++)\n {\n UniTask.Awaiter awaiter;\n try\n {\n awaiter = tasks[i].GetAwaiter();\n }\n catch (Exception ex)\n {\n core.TrySetException(ex);\n continue;\n }\n\n if (awaiter.IsCompleted)\n {\n TryInvokeContinuation(this, awaiter);\n }\n else\n {\n awaiter.SourceOnCompleted(state =>\n {\n using (var t = (StateTuple)state)\n {\n TryInvokeContinuation(t.Item1, t.Item2);\n }\n }, StateTuple.Create(this, awaiter));\n }\n }\n }\n\n static void TryInvokeContinuation(WhenAllPromise self, in UniTask.Awaiter awaiter)\n {\n try\n {\n awaiter.GetResult();\n }\n catch (Exception ex)\n {\n self.core.TrySetException(ex);\n return;\n }\n\n if (Interlocked.Increment(ref self.completeCount) == self.tasksLength)\n {\n self.core.TrySetResult(AsyncUnit.Default);\n }\n }\n\n public void GetResult(short token)\n {\n TaskTracker.RemoveTracking(this);\n GC.SuppressFinalize(this);\n core.GetResult(token);\n }\n\n public UniTaskStatus GetStatus(short token)\n {\n return core.GetStatus(token);\n }\n\n public UniTaskStatus UnsafeGetStatus()\n {\n return core.UnsafeGetStatus();\n }\n\n public void OnCompleted(Action continuation, object state, short token)\n {\n core.OnCompleted(continuation, state, token);\n }\n }\n }\n}\n"