はじめに
今回はUniTaskCompletionSource
について紹介したいと思います。
UniTaskCompletionSource
を使うことで好きなタイミングで結果を確定させるUniTaskを生成することができます。
早速見ていきましょう。
UniTaskCompletionSource
new UniTaskCompletionSource()
からTrySetResult(), TrySetCanceled(), TrySetException()
が呼ばれるまで待つUniTask
をUniTaskCompletionSource.Task
から生成することができます。
public UniTask Task { [DebuggerHidden] get { return new UniTask(this, 0); }
実際に利用しているコードを見た方がわかりやすいでしょう。
public class UniTaskTest { [UnityTest] public IEnumerator UniTaskCompletionSourceTest() { // 返り値を持たないUniTaskを生成するUniTaskCompletionSourceを生成 var uts = new UniTaskCompletionSource(); var isSuccess = false; // 非同期でUniTaskをawaitする UniTask.Void(async () => { await uts.Task; isSuccess = true; }); // UniTaskを完了させて、awaitを抜けさせる uts.TrySetResult(); yield return null; Assert.AreEqual(isSuccess, true); } [UnityTest] public IEnumerator UniTaskCompletionSourceTest2() { // 返り値を持つUniTaskを生成するUniTaskCompletionSourceを生成 var uts = new UniTaskCompletionSource<int>(); // 非同期でUniTaskをawaitする UniTask.Void(async () => { var result = await uts.Task; Assert.AreEqual(result, 10); }); // UniTaskを完了させて、awaitを抜けさせる uts.TrySetResult(10); yield return null; yield return null; } [UnityTest] public IEnumerator UniTaskCompletionSourceTest3() { // 返り値を持たないUniTaskを生成するUniTaskCompletionSourceを生成 var uts = new UniTaskCompletionSource(); var isSuccess = false; // 非同期でUniTaskをawaitする UniTask.Void(async () => { try { await uts.Task; Assert.Fail(); } catch (OperationCanceledException) { isSuccess = true; } }); // UniTaskを完了させて、awaitを抜けさせる uts.TrySetCanceled(); yield return null; Assert.AreEqual(isSuccess, true); } [UnityTest] public IEnumerator UniTaskCompletionSourceTest4() { // 返り値を持たないUniTaskを生成するUniTaskCompletionSourceを生成 var uts = new UniTaskCompletionSource(); var isSuccess = false; // 非同期でUniTaskをawaitする UniTask.Void(async () => { try { await uts.Task; Assert.Fail(); } catch (NotImplementedException) { isSuccess = true; } }); // UniTaskを完了させて、awaitを抜けさせる uts.TrySetException(new NotImplementedException()); yield return null; Assert.AreEqual(isSuccess, true); } }
UniTask
の結果を確定させるメソッドは以下の3つのメソッドになります。
名前 | 意味 |
---|---|
TrySetResult(), TrySetResult(T) | 結果をセットする |
TrySetException(Exception) | ステータスを失敗状態にする |
TrySetCanceled(CancellationToken) | ステータスをキャンセル状態にする |
UniTaskCompletionSource Class | UniTask
UniTaskCompletionSource<T> Class | UniTask
またUniTaskCompletionSource
は一度結果を確定した後、再度上記のメソッドを読んで状態・結果を変化させることはできないので注意してください。
if ((UniTaskStatus)intStatus != UniTaskStatus.Pending) return false;
UniTask.Void
そういえば今まで何気なくUniTask.Void
というファクトリメソッドを使ってましたが、そういえば一度も紹介していなかったので紹介しておきます。
// <summary> /// helper of fire and forget void action. /// </summary> public static void Void(Func<UniTaskVoid> asyncAction) { asyncAction().Forget(); }
UniTask.Void
の引数に取ったFunc
は投げっぱなし(Fire and Forget
)として実行されます。
つまりは以下のコードと同じ意味ですね。
// UniTask.Voidを使ったもの UniTask.Void(async () => { await UniTask.Yield(); Debug.Log("hello"); }); ↓ // 愚直に書いたもの Hoge().Forget(); private async UniTaskVoid Hoge() { await UniTask.Yield(); Debug.Log("hello"); }
わざわざメソッドを定義するのが面倒くさいときは便利なので、使ってみると良いかもしれません。