2011/11/06 修正 TimerはHotだ(キリッ)と大嘘を書いてたので修正しましたm(_ _)m id:neueccさんに感謝です。
過去記事インデックス
- Reactive Extensions再入門 その1
- Reactive Extensions再入門 その2「IObservableインターフェースとIObserverインターフェース」
- Reactive Extensions再入門 その3「IObservableのファクトリメソッド」
前回に続いて今回も地味にIObservable
時間と共に値を発行するIObservable
ここでは時間と共に値を発行するIObservable
Observable.Timerメソッド
まず、一番直感的に理解に理解できると思われるTimerメソッドを使用します。Timerメソッドは名前の通り一定時間ごとに値を発行します。発行する値はTimerが実行された回数になります。いくつかオーバーロードがありますが、第一引数にタイマーを開始するまでの時間、第二引数にタイマーのインターバルをTimeSpan型で指定するオーバーロードが、一番使用頻度が高いと思います。コード例を下記に示します。
// 3秒後から1秒間隔で値を発行するIObservable<long>を作成する var source = Observable.Timer( TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(1)); // 購読 var subscription = source.Subscribe( i => Console.WriteLine("OnNext({0})", i), ex => Console.WriteLine("OnError({0})", ex.Message), () => Console.WriteLine("Completed()")); // 3秒後からOnNext(回数)が表示される Console.WriteLine("please enter key..."); Console.ReadLine(); // Observableが発行する値の購読を停止 Console.WriteLine("dispose method call."); subscription.Dispose(); // Disposeをすると値が発行されなくなる。 Console.WriteLine("please enter key..."); Console.ReadLine();
コメントにもある通り、上記のコードは3秒後から1秒間隔で値を発行するIObservable
please enter key... // ここから3秒何も表示されない OnNext(0) // 3秒たつと1秒間隔でOnNextが呼ばれる OnNext(1) OnNext(2) OnNext(3) OnNext(4) OnNext(5) dispose method call. // Enterを押してDisposeが呼ばれるとOnNextも止まる please enter key...
Observable.Intervalメソッド
次もTimerメソッドと同じように使用できるメソッドを紹介します。こちらはIntervalメソッドでTimeSpanを1つ渡すだけでシンプルに使用できます。Subscribeした時点からTimeSpanで指定した間隔で値を発行します。発行する値はTimerと同じで何回値を発行したかという数字になります。コード例を下記に示します。
// 500ms間隔で値を発行する var source = Observable.Interval(TimeSpan.FromMilliseconds(500)); // 購読 var subscription = source.Subscribe( i => Console.WriteLine("OnNext({0})", i), ex => Console.WriteLine("OnError({0})", ex.Message), () => Console.WriteLine("Completed()")); Console.WriteLine("please enter key..."); Console.ReadLine(); // Observableが発行する値の購読を停止 Console.WriteLine("dispose method call."); subscription.Dispose(); // Disposeをすると値が発行されても受け取らなくなる。 Console.WriteLine("please enter key..."); Console.ReadLine();
上記の例では500ms間隔で値を発行しています。Enterキーを押すとDisposeを読んで購読を停止して再度Enterキーが押されるまで待機します。実行結果を下記に示します。
please enter key... OnNext(0) OnNext(1) OnNext(2) OnNext(3) OnNext(4) OnNext(5) OnNext(6) dispose method call. please enter key...
この実行結果では6が表示されたタイミングでEnterキーを押してDisposeを実行しています。実行結果からは読み取れませんが、上記の実行結果はDisposeが実行されたあとに数秒間待機して購読が停止していることを確認しています。
Observable.Generateメソッド
次は、以前にも使用したGenerateメソッドを使用します。GenerateメソッドにはTimeSpanを受け取るオーバーロードがあり、これを使うことで指定した時間間隔で値を発行するIObservable
var source = Observable.Generate( // 0から 0, // i < 10以下の間繰り返す i => i < 10, // iは1ずつ増える i => ++i, // 発行する値はiの二乗 i => i * i, // 値は(発行する値 * 100)ms間隔で発行する i => TimeSpan.FromMilliseconds(i * 100)); // 購読 var subscription = source.Subscribe( i => Console.WriteLine("OnNext({0})", i), ex => Console.WriteLine("OnError({0})", ex.Message), () => Console.WriteLine("Completed()")); Console.WriteLine("please enter key..."); Console.ReadLine(); // Observableが発行する値の購読を停止 Console.WriteLine("dispose method call."); subscription.Dispose(); // Disposeをすると値が発行されても受け取らなくなる。 Console.WriteLine("please enter key..."); Console.ReadLine();
上記の例は(0 * 0 * 100)ms, (1 * 1 * 100)ms, (2 * 2 * 100)ms, (3 * 3 * 100)ms…(9 * 9 * 100)msと値の発行回数増える度にインターバルを長くとるようにしています。実行結果を下記に示します。
please enter key... OnNext(0) OnNext(1) OnNext(4) OnNext(9) OnNext(16) OnNext(25) OnNext(36) OnNext(49) OnNext(64) OnNext(81) Completed() dispose method call. please enter key...
上記実行例は、最後までEnterキーを押さずに実行した場合になります。途中でEnterキーを押した場合の実行例を下記に示します。
please enter key... OnNext(0) OnNext(1) OnNext(4) OnNext(9) OnNext(16) dispose method call. please enter key...
このようにDisposeを呼ぶとGenerateメソッドの処理を途中から購読しなくなります。
次回予告?
後1回か2回くらいファクトリ系メソッドをやったあとに、ちょっと面白い(と個人的に思ってる)ところに入っていこうと思います。正直たんたんと値発行しては表示するだけのサンプルに飽きてきました!でもあと2回やります。