【Unity】【C#】UnityのメソッドをawaitできるようにするGetAwaiter()の紹介からのUniRxへの招待

Unityのメソッドをawaitできるようにする方法と、UniRxを導入すればすべて解決するよという話です。

Unity2018.2
UniRx6.2.2
C#6

Unityのメソッドをawaitしたい

async/awaitは便利なのでUnityのResource.LoadAsync()とかUnityで定義されているメソッドもこんな感じでawaitしたいものです。

var request = Resources.LoadAsync<Texture>("texture_example");
await request;
Debug.Log(request.asset as Texture2D);

ただ何も対応しないままこう書くと、次のようなコンパイルエラーが出ます。

f:id:halya_11:20190106140641p:plain

GetAwaiter()という拡張メソッドが必要らしいです。

GetAwaiter()を定義する

じゃあGetAwaiter()を定義しましょう。
GetAwaiterはこんな感じで拡張メソッドとして定義します。

using UnityEngine;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;

public static class ResourceRequestExtenion
{
    // Resources.LoadAsyncの戻り値であるResourceRequestにGetAwaiter()を追加する
    public static TaskAwaiter<Object> GetAwaiter(this ResourceRequest resourceRequest)
    {
        var tcs = new TaskCompletionSource<Object>();
        resourceRequest.completed += operation =>
        {
            // ロードが終わった時点でTaskCompletionSource.TrySetResult
            tcs.TrySetResult(resourceRequest.asset);
        };

        // TaskCompletionSource.Task.GetAwaiter()を返す
        return tcs.Task.GetAwaiter();
    }
}

コメントで大体はわかるかと思いますが、本記事の主旨とずれるので詳しい説明はしません。
このようにしてGetAwaiter()を定義するとResources.LoadAsync()がawaitできるようになります。

f:id:halya_11:20190106141150p:plain

UniRxを使えばすべて解決

このようにUnityのメソッドにGetAwaiter()を定義していけばawaitはできるわけですが、
実はこれらの拡張メソッドはすでにUniRxに定義されています。

そのためUniRxをusingするだけで普通にawaitできちゃいます。

using UnityEngine;
using System.Threading.Tasks;
using UniRx;

public class Example : MonoBehaviour {

    private async Task Start()
    {
        var request = Resources.LoadAsync<Texture>("texture_example");
        await request;
        Debug.Log(request.asset as Texture2D);
    }
}

UniRxはAssetStoreからダウンロードできます。

assetstore.unity.com

GetAwaiter()の詳細

本記事の結論としてはUniRxを入れちゃいましょうって話なのですが、
GetAwaiter()を自分で書かなければいけないこともあるかと思います。

その場合は下記の記事でわかりやすく説明されているので参照することをお勧めします(丸投げ)。

qiita.com

参考

qiita.com

assetstore.unity.com

関連

light11.hatenadiary.com

light11.hatenadiary.com