UniTaskの例外処理についてまとめました。
Unity2020.1.10
UniTask 2.0.37
非同期タスクを待機する場合
まず非同期タスクをawaitで待機する場合には同期メソッドと同じようにtry-catchでハンドリングできます。
またUnityのConsoleにエラーログとして例外の内容が出力されます。
using System; using System.Threading.Tasks; using Cysharp.Threading.Tasks; using UnityEngine; public class Example : MonoBehaviour { private async void Start() { // 例外の内容のエラーログが出力される // try-catchでハンドリングできる await SomeProcessAsync(); } private async UniTask SomeProcessAsync() { await UniTask.RunOnThreadPool(() => throw new Exception("ExampleException")); } }
このあたりは普通のTaskと同様の挙動です。
非同期タスクを待機しないと未処理例外として処理される
一方で、非同期タスクを待機しない場合にはtry-catchできません。
この場合にはGCが走ったタイミングで未処理例外として処理されます。
(このバージョンの)UniTaskでは未処理例外のデフォルトの挙動として、例外がスローされます。
using System; using System.Threading.Tasks; using Cysharp.Threading.Tasks; using UnityEngine; public class Example : MonoBehaviour { private async void Start() { // try-catchできない // GCのタイミングで例外が出力される SomeProcessAsync().Forget(); } private async UniTask SomeProcessAsync() { await UniTask.RunOnThreadPool(() => throw new Exception("ExampleException")); } }
未処理例外のログ出力タイプを変える
前節の方法では未処理例外のハンドリング方法として例外がスローされました。
UniTaskScheduler.UnobservedExceptionWriteLogType
を変更することで未処理例外のログ出力方法を変更できます。
以下では未処理例外発生時にWarningが発生するようにしています。
using System; using System.Threading.Tasks; using Cysharp.Threading.Tasks; using UnityEngine; public class Example : MonoBehaviour { private async void Start() { UniTaskScheduler.UnobservedExceptionWriteLogType = LogType.Warning; // try-catchできない SomeProcessAsync().Forget(); } private async UniTask SomeProcessAsync() { await UniTask.RunOnThreadPool(() => throw new Exception("ExampleException")); } }
これで未処理例外発生時にUnobservedTaskException: System.Exception: ExampleException
みたいなメッセージと共に警告が出力されるようになりました。
未処理例外のハンドリング処理を書き換える
またUniTaskScheduler.UnobservedTaskException
で未処理例外のハンドリング処理を上書きすることもできます。
using System; using Cysharp.Threading.Tasks; using UnityEngine; public class Example : MonoBehaviour { private async void Start() { // 未処理例外のハンドリング処理を書き換える UniTaskScheduler.UnobservedTaskException += HandleUnobservedTaskExceptions; SomeProcessAsync().Forget(); } private async UniTask SomeProcessAsync() { await UniTask.RunOnThreadPool(() => throw new Exception("ExampleException")); } private static void HandleUnobservedTaskExceptions(Exception ex) { Debug.LogError("未処理例外発生: " + ex); } }
再生すると書き換えた内容が反映されていることが確認できます。