かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

Reactive Extensions再入門 その10「Doメソッド」

2011/11/29 追記
Doメソッドの多用に注意する旨を追記しました。
2011/12/10
注意点を修正しました。

はじめに

軽いRxネタで息抜きです。今回はDoです。恐らく?一番簡単なんじゃないかと思います。

Doメソッド

ここでは、Doメソッドについて説明します。DoメソッドはIObservableから発行された値を受けて処理を行うだけのメソッドです。5.4.1のDrag処理でも使用しましたが、要素を受け取って処理を行いIObservableの要素に対しては何も加工を行ったりしません。コード例を下記に示します。

var subject = new Subject<int>();
subject
    // 途中に処理を挟む
    .Do(i => Console.WriteLine("Do : {0}", i))
    // 購読(購読しないとOnNextをしても値が流れないね)
    .Subscribe(i => Console.WriteLine("OnNext : {0}", i));

// 値の発行
subject.OnNext(1);
subject.OnNext(2);
subject.OnNext(3);

このコードを実行すると、Subscribeで値を購読している処理の前にDoの処理が行われていることが確認出来ます。
>|||
Do : 1
OnNext : 1
Do : 2
OnNext : 2
Do : 3
OnNext : 3
|

Doメソッドには、OnNextに対応する処理だけではなくOnErrorやOnCompleted時の処理を指定することも出来ます。このオーバーロードはSubscribeと同じでOnErrorにはActionを、OnCompletedには引数なしのActionを渡します。OnErrorの場合のコード例を下記に示します。

var subject = new Subject<int>();
subject
    // 途中に処理を挟む
    .Do(
        i => Console.WriteLine("Do : OnNext : {0}", i),
        ex => Console.WriteLine("Do : OnError : {0}", ex),
        () => Console.WriteLine("Do : OnCompleted"))
    // 購読(購読しないとOnNextをしても値が流れないね)
    .Subscribe(
        i => Console.WriteLine("OnNext : {0}", i),
        ex => Console.WriteLine("OnError : {0}", ex),
        () => Console.WriteLine("OnCompleted"));
// 値の発行
subject.OnNext(1);
subject.OnError(new Exception());

実行結果を下記に示します。

Do : OnNext : 1
OnNext : 1
Do : OnError : System.Exception: 種類 'System.Exception' の例外がスローされました。
OnError : System.Exception: 種類 'System.Exception' の例外がスローされました。

最後にOnCompletedの場合のコード例を下記に示します。

var subject = new Subject<int>();
subject
    .Do(
        i => Console.WriteLine("Do : OnNext : {0}", i),
        ex => Console.WriteLine("Do : OnError : {0}", ex),
        () => Console.WriteLine("Do : OnCompleted"))
    // 購読(購読しないとOnNextをしても値が流れないね)
    .Subscribe(
        i => Console.WriteLine("OnNext : {0}", i),
        ex => Console.WriteLine("OnError : {0}", ex),
        () => Console.WriteLine("OnCompleted"));

// 値の発行
subject.OnNext(1);
subject.OnCompleted();

実行結果を下記に示します。

Do : OnNext : 1
OnNext : 1
Do : OnCompleted
OnCompleted

このように、Doメソッドを使うとIObservableのシーケンスを処理する途中に任意のアクションを実行できます。

Doメソッド使用時の注意点

DoメソッドはReactive Extensionsの処理の中に任意のアクションを実行できるという便利なメソッドですが、本来は外部に対して副作用を起こさないReactive Extensionsの処理の中で副作用を起こすためのメソッドになります。そのため、Doメソッドの利用は必要最低限にとどめてください。Doメソッド以外の代替メソッドがある場合はそれを使用するように心がけましょう。また、複数のDoメソッドでフラグ変数を共有して挙動を変えるなど、動作が複雑化してきた場合は、一度立ち止まり本当にそれが必要か考えるようにすることをお勧めします。