はじめに
今回はUnity2023.1から登場したAwaitable
に関連した、AwaitableCompletionSource
について紹介をしたいと思います。
概要
まずは公式ドキュメントに書いてある説明から見てみましょう。
Objects allowing to control completion of an Awaitable object from user code.
// DeepL翻訳
ユーザーコードからAwaitableオブジェクトの完了を制御することができるオブジェクトです。
Task
で言うところのTaskCompletionSource
、UniTask
で言うところのUniTaskCompletionSource
のAwaitable
バージョンになります。
learn.microsoft.com
www.hanachiru-blog.com
ざっと言うと好きなタイミングでAwaitable
もしくはAwaitable<T>
の結果 or キャンセル or エラーをセットできる機能でしょうか。
private async Awaitable Start() { AwaitableCompletionSource<int> acs = new AwaitableCompletionSource<int>(); Awaitable<int> awaitable = acs.Awaitable; // Fire and Forget _ = SetResult(acs, destroyCancellationToken); // 1秒後まで待ち、結果が確定 var result = await awaitable; // 10 Debug.Log(result); } private static async Awaitable SetResult(AwaitableCompletionSource<int> acs, CancellationToken token) { await Awaitable.WaitForSecondsAsync(1, token); acs.SetResult(10); }
使い方
重要なメソッドは以下の通り。
AwaitableCompletionSource.SetResult
AwaitableCompletionSource.TrySetResult
AwaitableCompletionSource.SetCanceled
AwaitableCompletionSource.TrySetCanceled
AwaitableCompletionSource.SetException
AwaitableCompletionSource.TrySetException
await
した際の返り値がある場合はAwaitableCompletionSource<T>
を利用します。
private async Awaitable Start() { // ---------------- // 返り値なしバージョン // ---------------- AwaitableCompletionSource acs = new AwaitableCompletionSource(); Awaitable awaitable = acs.Awaitable; // Fire and Forget _ = SetResult(acs, destroyCancellationToken); // 1秒後まで待ち、結果が確定 await awaitable; // ---------------- // 返り値ありバージョン // ---------------- AwaitableCompletionSource<int> acs2 = new AwaitableCompletionSource<int>(); Awaitable<int> awaitable2 = acs2.Awaitable; _ = SetResult2(acs2, destroyCancellationToken); // 1秒後まで待つ var result = await awaitable2; // 10 Debug.Log(result); // ---------------- // キャンセルさせる // ---------------- AwaitableCompletionSource<int> acs3 = new AwaitableCompletionSource<int>(); Awaitable<int> awaitable3 = acs3.Awaitable; _ = SetCanceled(acs3, destroyCancellationToken); // 1秒後まで待つ try { var result3 = await awaitable3; } catch (OperationCanceledException) { Debug.Log("ここを通る"); } // ---------------- // エラーを発生させる // ---------------- AwaitableCompletionSource<int> acs4 = new AwaitableCompletionSource<int>(); Awaitable<int> awaitable4 = acs4.Awaitable; _ = SetException(acs4, destroyCancellationToken); try { var result4 = await awaitable4; } catch (NotImplementedException) { Debug.Log("ここを通る"); } } private static async Awaitable SetResult(AwaitableCompletionSource acs, CancellationToken token) { // 1秒後に結果を確定する await Awaitable.WaitForSecondsAsync(1, token); acs.SetResult(); } private static async Awaitable SetResult2(AwaitableCompletionSource<int> acs, CancellationToken token) { // 1秒後に結果を確定する await Awaitable.WaitForSecondsAsync(1, token); acs.SetResult(10); } private static async Awaitable SetCanceled(AwaitableCompletionSource<int> acs, CancellationToken token) { // 1秒後にキャンセルする await Awaitable.WaitForSecondsAsync(1, token); acs.SetCanceled(); } private static async Awaitable SetException(AwaitableCompletionSource<int> acs, CancellationToken token) { // 1秒後にエラーをセットする await Awaitable.WaitForSecondsAsync(1, token); acs.SetException(new NotImplementedException()); }