Skip to content

Catch

1. 概要

Catch は、ソース Observable が致命的エラー(OnCompleted(Result.Failure))で完了した際に、代替の Observable に切り替えてシーケンスを継続するオペレーターです。ソースが正常に完了した場合、代替 Observable は使用されません。

2. シグネチャ

固定の代替 Observable を指定するオーバーロード

csharp
public static Observable<T> Catch<T>(
    this Observable<T> source,
    Observable<T> second)

ソースが失敗で完了した場合、事前に指定した second Observable を購読して後続の要素を発行します。エラーの内容に関わらず、常に同じ代替シーケンスが使用されます。

例外に応じて代替 Observable を生成するオーバーロード

csharp
public static Observable<T> Catch<T, TException>(
    this Observable<T> source,
    Func<TException, Observable<T>> errorHandler)
    where TException : Exception

ソースが失敗で完了した場合、例外オブジェクトを errorHandler に渡し、返された Observable を購読します。例外の型や内容に応じて異なるリカバリ処理を行いたい場合に使用します。TException で型フィルタリングが可能で、一致しない例外型の場合はそのまま失敗として伝播します。

オーバーロード の使い分け

オーバーロード使用場面
Catch(source, second)フォールバック先が固定で、エラーの種類を問わずに代替シーケンスに切り替えたい場合
Catch(source, errorHandler)エラーの型・内容に応じて動的にリカバリ先を決定したい場合

3. マーブルダイアグラム

Catch のマーブルダイアグラム

ソースシーケンスが致命的エラー(OnCompleted(Result.Failure))で終了すると、代替 Observable への購読が開始され、代替シーケンスの要素がそのまま流れます。ソースが正常に完了した場合は、代替 Observable は購読されずにそのまま完了します。

4. サンプルコード

固定の代替 Observable による基本的なフォールバック

csharp
using R3;

// メインソースが失敗した場合にフォールバック値を返す
var fallback = Observable.Return("default-value");

var source = Observable.Create<string>(observer =>
{
    observer.OnNext("data-1");
    observer.OnNext("data-2");
    // 致命的エラーで完了
    observer.OnCompleted(Result.Failure(new InvalidOperationException("接続失敗")));
    return Disposable.Empty;
});

source
    .Catch(fallback)
    .Subscribe(
        value => Console.WriteLine($"値: {value}"),
        result => Console.WriteLine($"完了: {result}")
    );

// 出力:
// 値: data-1
// 値: data-2
// 値: default-value
// 完了: Success

例外の型に応じたリカバリ処理

csharp
using R3;

var source = Observable.Create<int>(observer =>
{
    observer.OnNext(1);
    observer.OnCompleted(Result.Failure(new TimeoutException("タイムアウト")));
    return Disposable.Empty;
});

source
    .Catch((TimeoutException ex) =>
    {
        Console.WriteLine($"タイムアウト発生: {ex.Message}、キャッシュに切り替え");
        return Observable.Create<int>(observer =>
        {
            observer.OnNext(-1); // キャッシュ値
            observer.OnCompleted();
            return Disposable.Empty;
        });
    })
    .Subscribe(
        value => Console.WriteLine($"値: {value}"),
        result => Console.WriteLine($"完了: {result}")
    );

// 出力:
// 値: 1
// タイムアウト発生: タイムアウト、キャッシュに切り替え
// 値: -1
// 完了: Success

5. 補足

IgnoreOnErrorResume との比較

CatchIgnoreOnErrorResume はどちらもエラーハンドリングオペレーターですが、対象とするエラーの種類が異なります。

特性CatchIgnoreOnErrorResume
対象エラー致命的エラー (OnCompleted(Result.Failure))非致命的エラー (OnErrorResume)
動作代替 Observable に切り替えるエラー通知を無視して継続する
シーケンスの継続代替シーケンスとして継続同一シーケンスが継続

両者を組み合わせることで、非致命的エラーは無視しつつ致命的エラーにはフォールバックで対処する、といった堅牢なエラーハンドリングパイプラインを構築できます。