以下の内容はhttps://yotiky.hatenablog.com/entry/unity_exceptionhandleより取得しました。


Unity - 横断的な例外処理

UniRxやUniTaskなどを使った場合の横断的な例外処理についてのメモ書き。

基本的にUniRxでのExceptionは、ストリームが壊れないように堅牢な方向に機能が実装されている。ストリームの内から外へ例外を搬出するのは楽ではない。そういう閉じた世界(例えば画面単位など)で使うのがベターそう。

SubjectのSubscribeのonErrorコールバック引数

  • ストリームで起きたエラーが入ってくる
  • Subscribeで起きたエラーは入らない
.Subscribe(
    _ => throw new Exception(),
    e => Debug.Log("ここには来ない"));

前段にDoをかます

  • 後段のSubscribeのonErrorに流れる
.Do(_ => throw new Exception())
.Subscribe(
    _ => {},
    e => Debug.Log("ここには来る"));
  • ただし、Do(async _ => xxx)と非同期にしてると流れない
  • 間にObserveOnMainThreadしてもダメ
.Do(async _ => throw new Exception())
.Subscribe(
    _ => {},
    e => Debug.Log("ここには来ない"));

ストリームからのthrow

  • throwしてもストリームの外には伝搬しない
  • 外でUniTaskCompletionSourceで状態待機してる場合は、completed.TrySetException(e)で外のタスクに例外を起こさせることができる
.Do(_ => throw new Exception())
.Subscribe(
    _ => {},
    e => _completed.TrySetException(e));

ReactivePropertyのストリーム

  • Subjectと同じ

MessageBrokerでPub/Sub

  • 使い方と使うとこ絞れば便利そう
// Pub
MessageBroker.Default.Publish(new AbortApplicationException());

// Sub
MessageBroker.Default.Receive<AbortApplicationException>()
    .Subscribe(_ =>
    {
        Debug.LogError("MessageBroker.AbortApplicationException");
        GoToTitle();
    })
    .AddTo(this);

Lopp + while のステートマシン

  • 例外が自然に伝搬するのでこれが楽そう
private async UniTask MainLoop()
{
    while(current != State.End)
    {
        switch(current)
        {
            // 各ステートの処理
            case State.Start:
                await Hoge();
                current = State.Next;
                break;
        }
        await UniTask.Yield();
    }
}

AsyncReactiveProperty

  • WaitAsyncだとタイミングで取りこぼして停止してしまう
private async UniTask MainLoop()
{
    while(current.Value != State.End)
    {
        // 取りこぼして停止する可能性がある
        var next = await current.WaitAsync();
        switch(next)
        {
            // 各ステートの処理
            case State.Start:
                await Hoge();
                current = State.Next;
                break;
        }
    }
}
  • UniTask.LinqQueueを挟んでメソッドチェーンであれば、例外の伝搬もされる
private async UniTask MainLoop()
{
    await current
        .WithoutCurrent() // 初期値無視
        .Queue() // 取りこぼし防止
        .ForEachAwaitAsync(async x =>
        {
            switch(x)
            {
                // 各ステートの処理
                throw new Exception();
            }
        });
}

UnhandledExceptionっぽいやつ

  • 動かなかったり扱いが難しそうだったりで使えないかも
AppDomain.CurrentDomain.UnhandledException +=
    (_, args) => Debug.LogError("AppDomain.CurrentDomain.UnhandledException " + args.ExceptionObject);

UniTaskScheduler.UnobservedTaskException +=
    exception => Debug.LogError("UniTaskScheduler.UnobservedTaskException " + exception);

Application.logMessageReceivedThreaded +=
    (condition, trace, type) => Debug.Log($"Application.logMessageReceivedThreaded {type}: {condition} ({trace})");

参考




以上の内容はhttps://yotiky.hatenablog.com/entry/unity_exceptionhandleより取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14