はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】UniTask.WhenAllは省略できて、配列かIEnumerableかTupleをawaitしてあげるだけでも同じ意味になる

はじめに

UniTask.WhenAllを利用することで全てのTaskが終了するまで待つことができます。

// 全てのTaskが終わるまで待つ
await UniTask.WhenAll(UniTask.Delay(1), UniTask.Delay(2), UniTask.Delay(3));

実はこれはいくつか書き方があるので、それを紹介したいと思います。

github.com

書き方

配列、IEnumerableTupleawaitしても同様の処理を実現できます。

var task1 = UniTask.Delay(1);
var task2 = UniTask.Delay(2);
var task3 = UniTask.Delay(3);

// パターン1 (UniTask.WhenAllを使う)
await UniTask.WhenAll(task1, task2, task3);

// パターン2 (this UniTask[] tasks)
await new[]
{
    task1,
    task2,
    task3
};

// パターン3 (this IEnumerable<UniTask> tasks)
await new List<UniTask>
{
    task1,
    task2,
    task3
};

// パターン4 (Tupleを利用したパターン)
await (task1, task2, task3);

ただアロケーション的な観点でいうとTupleを利用する方が優秀なはず(要調査)なので、それを積極的に利用するといいでしょう。

実現しているコード

#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System.Collections.Generic;

namespace Cysharp.Threading.Tasks
{
    public static partial class UniTaskExtensions
    {
        // shorthand of WhenAll
    
        public static UniTask.Awaiter GetAwaiter(this UniTask[] tasks)
        {
            return UniTask.WhenAll(tasks).GetAwaiter();
        }

        public static UniTask.Awaiter GetAwaiter(this IEnumerable<UniTask> tasks)
        {
            return UniTask.WhenAll(tasks).GetAwaiter();
        }

        public static UniTask<T[]>.Awaiter GetAwaiter<T>(this UniTask<T>[] tasks)
        {
            return UniTask.WhenAll(tasks).GetAwaiter();
        }

        public static UniTask<T[]>.Awaiter GetAwaiter<T>(this IEnumerable<UniTask<T>> tasks)
        {
            return UniTask.WhenAll(tasks).GetAwaiter();
        }

        public static UniTask<(T1, T2)>.Awaiter GetAwaiter<T1, T2>(this (UniTask<T1> task1, UniTask<T2> task2) tasks)
        {
            return UniTask.WhenAll(tasks.Item1, tasks.Item2).GetAwaiter();
        }

        // ...

        public static UniTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15)>.Awaiter GetAwaiter<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(this (UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8, UniTask<T9> task9, UniTask<T10> task10, UniTask<T11> task11, UniTask<T12> task12, UniTask<T13> task13, UniTask<T14> task14, UniTask<T15> task15) tasks)
        {
            return UniTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8, tasks.Item9, tasks.Item10, tasks.Item11, tasks.Item12, tasks.Item13, tasks.Item14, tasks.Item15).GetAwaiter();
        }



        public static UniTask.Awaiter GetAwaiter(this (UniTask task1, UniTask task2) tasks)
        {
            return UniTask.WhenAll(tasks.Item1, tasks.Item2).GetAwaiter();
        }

        // .....

        public static UniTask.Awaiter GetAwaiter(this (UniTask task1, UniTask task2, UniTask task3, UniTask task4, UniTask task5, UniTask task6, UniTask task7, UniTask task8, UniTask task9, UniTask task10, UniTask task11, UniTask task12, UniTask task13, UniTask task14, UniTask task15) tasks)
        {
            return UniTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8, tasks.Item9, tasks.Item10, tasks.Item11, tasks.Item12, tasks.Item13, tasks.Item14, tasks.Item15).GetAwaiter();
        }
    }
}

github.com