過去記事インデックス
- Reactive Extensions再入門 その1
- Reactive Extensions再入門 その2「IObservableインターフェースとIObserverインターフェース」
- Reactive Extensions再入門 その3「IObservableのファクトリメソッド」
- Reactive Extensions再入門 その4「Timer系のファクトリメソッド」
- Reactive Extensions再入門 その5「HotとCold」
- Reactive Extensions再入門 その6「HotなIObservableを作成するファクトリ」
- Reactive Extensions再入門 その7「LINQスタイルの拡張メソッド」
- Reactive Extensions再入門 その8「SkipとTakeメソッド」
- Reactive Extensions再入門 その9「Skip + Take + Repeat = ドラッグ」
- Reactive Extensions再入門 その10「Doメソッド」
- Reactive Extensions再入門 その11「Catchメソッド」
- Reactive Extensions再入門 その12「Finallyメソッドとリソース解放」
- Reactive Extensions再入門 その13「最後の値を取得するLatestとMostRecentメソッド」
- Reactive Extensions再入門 その14「Nextメソッド」
- Reactive Extensions再入門 その15「To*****系メソッド」
- Reactive Extensions再入門 その16「最大、最少、平均を求めるメソッド」
- Reactive Extensions再入門 その17「集計するメソッド」
- Reactive Extensions再入門 その18「CountメソッドとLongCountメソッド」
- Reactive Extensions再入門 その19「AnyメソッドとAllメソッド」
- Reactive Extensions再入門 その20「GroupByメソッドでグルーピングしてみよう」
- Reactive Extensions再入門 その21「GroupByUntilメソッド」
- Reactive Extensions再入門 その22「単一の値を取得するメソッド」
- Reactive Extensions再入門 その23「重複を排除するメソッド」
- Reactive Extensions再入門 その24「単一の値を取得するメソッド その2」
- Reactive Extensions再入門 その25「値をまとめるBufferメソッド」
- Reactive Extensions再入門 その26「値をまとめるWindowメソッド」
- Reactive Extensions再入門 その27「時間でフィルタリング?Sampleメソッド」
- Reactive Extensions再入門 その28「落ち着いたら流すThrottleメソッド」
- Reactive Extensions再入門 その29「値を指定した時間だけ遅延させるDelayメソッド」
- Reactive Extensions再入門 その30「もう待ちきれない!を表現するTimeoutメソッド」
- Reactive Extensions再入門 その31「時間に関する情報を付与するTimestampとTimeIntervalメソッド」
- Reactive Extensions再入門 その32「型変換を行うCastとOfTypeメソッド」
- Reactive Extensions再入門 その33「シーケンスの最後を起点にSkipとTake」
- Reactive Extensions再入門 その34「ダメなら次の人!を実現するOnErrorResumeNextメソッド」
- Reactive Extensions再入門 その35「駄目ならやり直す!を実現するRetryメソッド」
- Reactive Extensions再入門 その36「ColdからHotへ!Publishメソッドと参照カウンタ?RefCountメソッド」
- Reactive Extensions再入門 その37「ColdからHotへ!その他のPublish系メソッド」
- Reactive Extensions再入門 その38「ColdからHotへ!その他のPublish系メソッド2」
- Reactive Extensions再入門 その39「Subject系クラス」
- Reactive Extensions再入門 その40「IObservableの合成はじめました」
- Reactive Extensions再入門 その41「どんどん合成するよ」
はじめに
今回も、前回に続いて合成する関係のメソッドを使ってみようと思います。
StartWithメソッド
ここでは、StartWithメソッドについて説明します。StartWithメソッドのシグネチャを以下に示します。
public static IObservable<T> StartWith<T>(this IObservable<T> source, params T[] values);
このメソッドは、sourceで渡したIObservable
Observable // 1〜3の値を発行するIObservable<T>のシーケンス .Range(1, 3) // 頭に10, 20, 30をつける .StartWith(10, 20, 30) // 購読 .Subscribe( i => Console.WriteLine("OnNext: {0}", i));
Rangeメソッドを使って1〜3の値を発行するIObservable
OnNext: 10 OnNext: 20 OnNext: 30 OnNext: 1 OnNext: 2 OnNext: 3
Joinメソッド
ここでは、Joinメソッドについて説明します。Joinメソッドは2つのIObservable
public static IObservable<TResult> Join<TLeft, TRight, TLeftDuration, TRightDuration, TResult>( this IObservable<TLeft> left, IObservable<TRight> right, Func<TLeft, IObservable<TLeftDuration>> leftDurationSelector, Func<TRight, IObservable<TRightDuration>> rightDurationSelector, Func<TLeft, TRight, TResult> resultSelector);
Joinメソッドは、leftとrightから値が発行されると、それぞれleftDurationSelector引数とrightDurationSelector引数で指定したデリゲートが呼ばれて、その値の有効期間を示すIObservable
このメソッドのコード例を下記に示します。
// Joinで合成するIObservable<T> var left = new Subject<int>(); var right = new Subject<int>(); left.Join( right, // leftから発行される値の有効期間は永久 _ => Observable.Never<Unit>(), // rightから発行される値の有効期間は永久 _ => Observable.Never<Unit>(), // 発行された値の組を作る Tuple.Create) // 購読 .Subscribe( // 組を表示 tuple => Console.WriteLine("Left: {0}, Right: {1}", tuple.Item1, tuple.Item2), // 完了を表示 () => Console.WriteLine("OnCompleted")); // 値の発行 Console.WriteLine("left.OnNext(1)"); left.OnNext(1); Console.WriteLine("right.OnNext(10)"); right.OnNext(10); Console.WriteLine("right.OnNext(100)"); right.OnNext(100); Console.WriteLine("left.OnNext(2)"); left.OnNext(2); // 終了 Console.WriteLine("left.OnCompleted()"); left.OnCompleted(); Console.WriteLine("right.OnCompleted()"); right.OnCompleted();
Joinメソッドを使って2つのIObservable
left.OnNext(1) ← この段階ではleftに1があるだけ right.OnNext(10) ← この段階でleftに1, rightに10があるため(1, 10)の組が生成される Left: 1, Right: 10 right.OnNext(100) ← この段階でleftに1, rightに10, 100があるため (1, 100)の組が追加で生成される Left: 1, Right: 100 left.OnNext(2) ← この段階でleftに1, 2, rightに10, 100があるため(2, 10), (2, 100)の組が追加で生成される Left: 2, Right: 10 Left: 2, Right: 100 left.OnCompleted() right.OnCompleted() OnCompleted ← rightとleftが両方終了したため、これ以降新たな組み合わせが出来ないため終了
この例のように値の有効期間にObservable.Neverを使うと、leftとrightから発行された全ての組合わせを生成することが出来ます。Never以外の値の有効期間を指定したときのコード例を下記に示します。
// Joinで合成するIObservable<T> var left = new Subject<int>(); var right = new Subject<int>(); left.Join( right, // leftから発行される値の有効期間は永久 _ => Observable.Never<Unit>(), // rightから発行される値の有効期間は一瞬 _ => Observable.Empty<Unit>(), // 発行された値の組を作る Tuple.Create) // 購読 .Subscribe( // 組を表示 tuple => Console.WriteLine("Left: {0}, Right: {1}", tuple.Item1, tuple.Item2), // 完了を表示 () => Console.WriteLine("OnCompleted")); // 値の発行 Console.WriteLine("left.OnNext(1)"); left.OnNext(1); Console.WriteLine("right.OnNext(10)"); right.OnNext(10); Console.WriteLine("right.OnNext(100)"); right.OnNext(100); Console.WriteLine("left.OnNext(2)"); left.OnNext(2); Console.WriteLine("right.OnNext(1000)"); right.OnNext(1000); // 終了 Console.WriteLine("left.OnCompleted()"); left.OnCompleted(); Console.WriteLine("right.OnCompleted()"); right.OnCompleted();
上記のコードはrightから発行された値の有効期間をObservable.Empty
left.OnNext(1) right.OnNext(10) Left: 1, Right: 10 right.OnNext(100) Left: 1, Right: 100 left.OnNext(2) right.OnNext(1000) Left: 1, Right: 1000 Left: 2, Right: 1000 left.OnCompleted() right.OnCompleted() OnCompleted
rightから値が発行されると、今までleftから発行された値との組み合わせが生成されていることが確認できます。逆にleftから値が発行されてもrightから発行された値には有効なものが1つもないため、resultSelectorで指定したデリゲートは呼ばれません。
ここでは、コード例を示しませんが、値の有効期限にタイマーやイベントなどから生成したIObservable