Unityでコルーチンのエラーハンドリングをやりやすくする拡張メソッドをつくってみました。
Unity2020.2.7
課題
Unityのコルーチン内で例外がスローされると後続の処理は実行されません。
// この中で例外が発生したら yield return StartCoroutine(routine); // この後の処理は呼ばれない Debug.Log("Finish.");
また、yieldはtry-catchの中には書けません。
try { // こう書けない yield return StartCoroutine(routine); } catch (Exception e) { // ハンドリング(できない) }
これではエラーハンドリングしたいときに困るので、拡張メソッドで対応する方法を紹介します。
実装
拡張メソッドの実装は以下の通りです。
public static class MonoBehaviourExtensions { /// <summary> /// コルーチンを開始する /// </summary> /// <param name="self"></param> /// <param name="routine"></param> /// <param name="throwException">発生した例外をスローするか</param> /// <param name="onError">例外発生時のコールバック</param> /// <returns></returns> public static Coroutine StartCoroutine(this MonoBehaviour self, IEnumerator routine, bool throwException = true, Action<Exception> onError = null) { return self.StartCoroutine(CreateRoutine(routine, throwException, onError)); } private static IEnumerator CreateRoutine(IEnumerator routine, bool throwException = true, Action<Exception> onError = null) { while (true) { object current = null; Exception ex = null; try { if (!routine.MoveNext()) { break; } current = routine.Current; } catch (Exception e) { ex = e; onError?.Invoke(e); if (throwException) { throw; } } if (ex != null) { yield return ex; yield break; } yield return current; } } }
throwExceptionをfalseにすると発生した例外をせず、その時点でコルーチンの終了だけを行います。
またonErrorで例外発生時のコールバックを設定できます。
使う
この拡張メソッドは以下のようにして使います。
private IEnumerator Start() { // 例外が発生してもスローせず、エラーログだけを出す yield return this.StartCoroutine(RoutineWithError(1.0f), false, Debug.LogError); // この処理も実行される Debug.Log("end"); } private IEnumerator RoutineWithError(float durationSec) { yield return new WaitForSeconds(durationSec); throw new Exception(); }