UniTaskにおいてキャンセル時に例外を発生させない SuppressCancellationThrow の使い方をまとめました。
SuppressCancellationThrowの使い方
UniTaskでは、引数に渡したCancellationTokenによりキャンセルが行われると、OperationCanceledExceptionが発生します。
using System; using System.Threading; using Cysharp.Threading.Tasks; using UnityEngine; public sealed class Example : MonoBehaviour { private readonly CancellationTokenSource _cancellationTokenSource = new(); private async void Start() { try { await UniTask.Delay(TimeSpan.FromSeconds(10), cancellationToken: _cancellationTokenSource.Token); } catch (OperationCanceledException) { Debug.Log("キャンセル発生"); throw; } } private void Update() { // スペースキーでキャンセル if (Input.GetKeyDown(KeyCode.Space)) { _cancellationTokenSource.Cancel(); } } }
これに対して、以下のようにSuppressCancellationThrow
を使うと、キャンセル時に例外をスローせず戻り値からキャンセル状態を取得できるようになります。
using System; using System.Threading; using Cysharp.Threading.Tasks; using UnityEngine; public sealed class Example : MonoBehaviour { private readonly CancellationTokenSource _cancellationTokenSource = new(); private async void Start() { var isCanceled = await UniTask .Delay(TimeSpan.FromSeconds(10), cancellationToken: _cancellationTokenSource.Token) .SuppressCancellationThrow(); // 戻り値からキャンセル状態を取得できる Debug.Log(isCanceled); } private void Update() { if (Input.GetKeyDown(KeyCode.Space)) { _cancellationTokenSource.Cancel(); } } }
戻り値ありの場合
戻り値ありの非同期メソッドの場合にSuppressCancellationThrow
を使うと、以下のようにキャンセル状態と結果の両方を取得できます。
using System; using System.Threading; using Cysharp.Threading.Tasks; using UnityEngine; public sealed class Example : MonoBehaviour { private readonly CancellationTokenSource _cancellationTokenSource = new(); private async void Start() { var result = await UniTask .Delay(TimeSpan.FromSeconds(10), cancellationToken: _cancellationTokenSource.Token) .ContinueWith(() => 123) .SuppressCancellationThrow(); if (!result.IsCanceled) Debug.Log(result.Result); else Debug.Log("Canceled"); } private void Update() { if (Input.GetKeyDown(KeyCode.Space)) _cancellationTokenSource.Cancel(); } }
使いどころ
使いどころとしては、例えば「ロードがキャンセルされなかった時のみ画像を設定する、キャンセルされたら何もしない」というようなケースが考えられます。
using System.Threading; using Cysharp.Threading.Tasks; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.UI; public sealed class Example : MonoBehaviour { [SerializeField] private RawImage image; public async void SetImageAsync(string resourceKey, CancellationToken cancellationToken) { var result = await Addressables.LoadAssetAsync<Texture2D>(resourceKey) .ToUniTask(cancellationToken: cancellationToken) .SuppressCancellationThrow(); if (result.IsCanceled) return; image.texture = result.Result; } }
ただし一般的には同期メソッドはキャンセル時に例外をスローすることが期待されるため、適用するスコープには注意が必要です。