C#でdelegateをTaskに変換してawaitできるようにする方法です。
Unity2019.2.5
やりたいこと
いま、下記のようにActionのコールバックをawaitで待ち受けたいとします。
using UnityEngine; using System; public class Example : MonoBehaviour { private Action<string> _exampleDelegate; private async void Start() { // _exampleDelegateが一回呼ばれるのをawaitで待機したい } }
このような場合にはdelegateをTaskに変換する必要があります。
この記事ではこの方法を説明します。
ちなみにasync/awaitの基本については以下の記事で説明していますので、必要に応じて参照してください。
delegateをTaskに変換するにはTaskCompiletionSourceを使う
このようなケースで便利なのがTaskCompiletionSourceというクラスです。
これを以下のように使えばdelegateをTaskに変換できます。
using UnityEngine; using System; using System.Threading.Tasks; public class Example : MonoBehaviour { private Action<string> _exampleDelegate; private async void Start() { // 待機できた var _ = await ExampleTask(); } private Task<string> ExampleTask() { var source = new TaskCompletionSource<string>(); void onReceiveEvent(string str){ source.SetResult(str); _exampleDelegate -= onReceiveEvent; } _exampleDelegate += onReceiveEvent; return source.Task; } }
非ジェネリックの場合
さて前節のTaskCompletetionSourceはジェネリック型のものしか定義されていません。
これでは上記のようにAction<string>
には対応できまするもののAction
には対応できません。
このような場合には適当に型を指定しまえばよいようです。
ソースコードはこんな感じです。
using UnityEngine; using System; using System.Threading.Tasks; public class Example : MonoBehaviour { private Action _exampleDelegate; private async void Start() { await ExampleTask(); } private Task ExampleTask() { var source = new TaskCompletionSource<bool>(); void onReceiveEvent(){ source.SetResult(true); _exampleDelegate -= onReceiveEvent; } _exampleDelegate += onReceiveEvent; return source.Task; } }