知識0からのUnityShader勉強

知識0からのUnityShader勉強

UnityのShaderをメインとして、0から学んでいくブログです。

【UniRx】エラーハンドリング系のオペレータ #102

前回の成果

非同期処理のオペレータをまとめた。

soramamenatan.hatenablog.com


今回やること

エラーハンドリング系のオペレータをまとめます。


例外発生時に、例外を補足せずに処理を行う

DoOnError

例外発生時にOnErrorメッセージを用いて処理を発生させます。
メッセージそのものは変更しません。

ソースコード
/// <summary>
/// 例外発生時に、例外を補足せずに処理を行う
/// </summary>
private void ExtionDoOnError() {
    Observable
        .Range(0, 1)
        .Do(_ => throw new Exception())
        .DoOnError(e => {
            Debug.Log("DoOnError : " + e);
        })
        .Subscribe(x => {
            Debug.Log("OnNext : " + x);
        }, e => {
            Debug.Log("OnError : " + e);
        }, () => {
            Debug.Log("OnCompleted");
        });
}
結果

DoOnErrorが発行され、SubscribeのOnErrorが発行されています。

f:id:soramamenatan:20210504145914p:plain


例外発生時に、購読し直す

Retry

例外が発生したときに、指定した回数ストリームを再購読します。

ソースコード
/// <summary>
/// 例外発生時に、Subscribeし直す
/// </summary>
private void ExcuteRetry() {
    Observable
        .Range(0, 1)
        .Do(_ => throw new Exception())
        .DoOnError(e => Debug.Log("DoOnError : " + e))
        // 3回繰り返す
        .Retry(3)
        .Subscribe(x => {
            Debug.Log("OnNext : " + x);
        }, e => {
            Debug.Log("OnError : " + e);
        }, () => {
            Debug.Log("OnCompleted");
        });
}
結果

引数で3を指定しているので、3回購読し直されています。
なので、DoOnErrorが3回呼ばれています。

f:id:soramamenatan:20210504150538p:plain


指定した型の例外の場合、購読し直す

OnErrorRetry

引数で例外を指定することができます。
指定した例外が来た場合に購読し直します。

ソースコード
public class ExceptionA : Exception { }
public class ExceptionB : Exception { }

/// <summary>
/// OnErrorRetryの実行
/// </summary>
private void ExcuteOnErrorRetry() {
    Debug.Log("------throw A------");
    OnErrorRetryThrowError(new ExceptionA());
    Debug.Log("------throw B------");
    OnErrorRetryThrowError(new ExceptionB());
}

/// <summary>
/// 指定した型の例外の場合、Subscribeし直す
/// </summary>
private void OnErrorRetryThrowError(Exception error) {
    Observable
        .Range(0, 1)
        .Do(_ => throw error)
        .DoOnError(e => Debug.Log("DoOnError : " + e))
        // ExceptionAが来た場合
        .OnErrorRetry((ExceptionA e) => {
            Debug.Log("OnErrorRetry A");
        }, 3)
        // ExceptionBが来た場合
        .OnErrorRetry((ExceptionB e) => {
            Debug.Log("OnErrorRetry B");
        }, 3)
        .Subscribe(x => {
            Debug.Log("OnNext : " + x);
        }, e => {
            Debug.Log("OnError : " + e);
        }, () => {
            Debug.Log("OnCompleted");
        });
}
結果

ExceptionAが例外に来た場合とExceptionBの場合でログが異なるのがわかります。

f:id:soramamenatan:20210504150910p:plain


例外発生時に、指定した回数、指定した間隔で購読し直す

DoOnError

第二引数に繰り返す回数を、第三引数にTimeSpanを指定することができます。

ソースコード
/// <summary>
/// 指定した回数、指定した間隔でSubscribeし直す
/// </summary>
private void ExcuteOnErrorRetryTime() {
    Observable
        .Range(0, 1)
        .Do(_ => throw new Exception())
        .DoOnError(e => Debug.Log("DoOnError : " + e))
        // 指定した回数、指定間隔で実行
        .OnErrorRetry((Exception e) => {
            Debug.Log("OnErrorRetry");
        }, 3, TimeSpan.FromSeconds(1))
        .Subscribe(x => {
            Debug.Log("OnNext : " + x);
        }, e => {
            Debug.Log("OnError : " + e);
        }, () => {
            Debug.Log("OnCompleted");
        });
}
結果

引数で指定した1秒毎に、計3回購読し直しています。
3回購読した後にはOnErrorを発行しています。

f:id:soramamenatan:20210504151229p:plain


例外発生時に、代わりのObservableを渡す

Catch

例外が発生した際に、その例外を処理して代わりのObservableを渡すことが出来ます。

ソースコード
/// <summary>
/// 例外発生時に、代わりのObservableを渡す
/// </summary>
private void ExcuteCatch() {
    Observable
        .Range(0, 1)
        .Select(x => x.ToString())
        .Do(_ => throw new Exception())
        .Catch((Exception e) => {
            // エラー処理の実行
            return Observable.Return("Catch");
        })
        .Subscribe(x => {
            Debug.Log("OnNext : " + x);
        }, e => {
            Debug.Log("OnError : " + e);
        }, () => {
            Debug.Log("OnCompleted");
        });
}
結果

本来OnNextに渡されるはずだった"1"が来ずに、"Catch"が渡されています。

f:id:soramamenatan:20210504151954p:plain


指定した型の例外発生時に、代わりのObservableを渡す

Catch

指定した型の例外が発生した際に、その例外を処理して代わりのObservableを渡すことが出来ます。

ソースコード
public class ExceptionA : Exception { }
public class ExceptionB : Exception { }

/// <summary>
/// 指定した型をCatchの実行
/// </summary>
private void ExcuteCatchTarget() {
    Debug.Log("------throw A------");
    CatchThrowError(new ExceptionA());
    Debug.Log("------throw B------");
    CatchThrowError(new ExceptionB());
}

/// <summary>
/// 指定した型の例外発生時に、代わりのObservableを渡す
/// </summary>
private void CatchThrowError(Exception error) {
    Observable
        .Range(0, 1)
        .Select(x => x.ToString())
        .Do(_ => throw error)
        // ExceptionAが来た場合
        .Catch((ExceptionA e) => {
            return Observable.Return("Catch A");
        })
        // ExceptionBが来た場合
        .Catch((ExceptionB e) => {
            return Observable.Return("Catch B");
        })
        .Subscribe(x => {
            Debug.Log("OnNext : " + x);
        }, e => {
            Debug.Log("OnError : " + e);
        }, () => {
            Debug.Log("OnCompleted");
        });
}
結果

本来OnNextに渡されるはずだった"1"が来ずに、"Catch ○"が渡されています。 また、ExceptionAを例外として投げた場合にはAが、
ExceptionBを例外として投げた場合にはBが返って来ています。

f:id:soramamenatan:20210504152223p:plain


Catch時にObservableを返さずにOnCompletedを発行

CatchIgnore

Catchしたときに、特に処理をせずにOnCompletedを呼びたい場合に使用します。

ソースコード
/// <summary>
/// Catch時にObservableを返さずにOnCompletedを発行
/// </summary>
private void ExcuteCatchIgnore() {
    Observable
        .Range(0, 1)
        .Select(x => x.ToString())
        .Do(_ => throw new Exception())
        .CatchIgnore((Exception e) => {
            Debug.Log("Catch Ignore : " + e);
        })
        .Subscribe(x => {
            Debug.Log("OnNext : " + x);
        }, e => {
            Debug.Log("OnError : " + e);
        }, () => {
            Debug.Log("OnCompleted");
        });
}
結果

すぐにOnCompletedが呼ばれています。

f:id:soramamenatan:20210504152544p:plain


今回は以上になります。
ここまでご視聴ありがとうございました。


参考サイト様

light11.hatenadiary.com

qiita.com