SlideShare une entreprise Scribd logo
1  sur  211
Télécharger pour lire hors ligne
Reactive Extensions 入門




          2012/03/05

            0.1 版

            okazuk
改版履歴

 版数    内容                  日付
 0.1   基本メソッドの説明を書いた初版作成   2012/03/05




                    ii
内容

1.     はじめに.............................................................................................................................................................. 1

     1.1.     前提環境 ............................................................................................................................................................ 1

     1.2.     対象読者 ............................................................................................................................................................ 1

     1.3.     謝辞 ................................................................................................................................................................... 1

2.     REACTIVE EXTENSIONS とは ........................................................................................................................ 2

     2.1.     OBSERVER パターン .......................................................................................................................................... 2

     2.2.     REACTIVE EXTENSIONS で提供されている機能 ................................................................................................ 2

     2.3.     IOBSERVALBE<T>゗ンターフェースと IOBSERVER<T>゗ンターフェース ..................................................... 3

     2.4.     REACTIVE EXTENSIONS の機能を使った書き直し ............................................................................................ 8

3.     IOBSERVABLE<T>のファクトリメソッド ...................................................................................................... 11

     3.1.     基本的なフゔクトリメソッドの使用 ............................................................................................................... 11

     3.2.     指定された値を返す IOBSERVABLE<T>を返すフゔクトリメソッド .............................................................. 12

       3.2.1.        Observable.Return メソッド ................................................................................................................. 12

       3.2.2.        Observable.Repeat メソッド.................................................................................................................. 12

       3.2.3.        Observable.Range メソッド ................................................................................................................... 13

       3.2.4.        Observable.Generate メソッド .............................................................................................................. 14

       3.2.5.        Observable.Defer メソッド .................................................................................................................... 15

       3.2.6.        Observable.Create メソッド .................................................................................................................. 17

       3.2.7.        Observable.Throw メソッド .................................................................................................................. 18

     3.3.     ここまでに紹介した IOBSERVABLE<T>の動作 ............................................................................................... 19

     3.4.     リソースの確保を伴う IOBSERVABLE<T> ...................................................................................................... 19

       3.4.1.        Observable.Uting メソッド .................................................................................................................... 20

     3.5.     時間と共に値を発行する IOBSERVABLE<T> .................................................................................................. 21

       3.5.1.        Observable.Timer メソッド ................................................................................................................... 21

       3.5.2.        Observable.Interval メソッド ................................................................................................................ 23

       3.5.3.        Observable.Generate メソッド .............................................................................................................. 24

     3.6.     COLD な IOBSERVABLE<T>と HOT な IOBSERVABLE<T> .............................................................................. 25

       3.6.1.        Observable.FromEvent メソッド .......................................................................................................... 28
                                                                                         i
3.6.2.       Observable.Start メソッド..................................................................................................................... 30

       3.6.3.       Observable.ToAsync メソッド ............................................................................................................... 32

       3.6.4.       Observable.FromAsyncPattern メソッド ............................................................................................. 33

4.     IOBSERVABLE の拡張メソッド ...................................................................................................................... 35

     4.1.    LINQ のメソッド ............................................................................................................................................ 35

     4.2.    単一の値を取得するメソッド ......................................................................................................................... 38

       4.2.1.       First メソッドと Last メソッド ............................................................................................................. 38

       4.2.2.       FirstOrDefault メソッドと LastOrDefault メソッド ........................................................................... 41

       4.2.3.       ElementAt メソッド ............................................................................................................................... 42

       4.2.4.       ElementAtOrDefault メソッド .............................................................................................................. 45

       4.2.5.       Single メソッド ....................................................................................................................................... 46

       4.2.6.       SingleOrDefault メソッド...................................................................................................................... 50

     4.3.    値と飛ばす、値を拾うメソッド ...................................................................................................................... 52

       4.3.1.       Skip と Take メソッド ............................................................................................................................ 52

       4.3.2.       Repeat メソッドとの組み合わせ ............................................................................................................ 53

       4.3.3.       SkipWhile と TakeWhile メソッド ........................................................................................................ 54

       4.3.4.       SkipUntil と TakeUntil メソッド .......................................................................................................... 55

       4.3.5.       SkipUntil と TakeUntil を使ったドラッグの処理 ................................................................................. 56

       4.3.6.       SkipLast と TakeLast メソッド ............................................................................................................. 61

     4.4.    DO メソッド .................................................................................................................................................... 62

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

     4.5.    エラー処理関連のメソッド ............................................................................................................................. 64

       4.5.1.       Catch メソッド ....................................................................................................................................... 64

       4.5.2.       Finally メソッド ..................................................................................................................................... 67

       4.5.3.       OnErrorResumeNext メソッド ............................................................................................................. 70

       4.5.4.       Retry メソッド ........................................................................................................................................ 72

     4.6.    IOBSERVABLE<T>の値を収集するメソッド ................................................................................................... 75

       4.6.1.       ToArray メソッド ................................................................................................................................... 75

       4.6.2.       ToDictionary メソッド ........................................................................................................................... 76

       4.6.3.       ToList メソッド ...................................................................................................................................... 77

       4.6.4.       ToLookup メソッド ................................................................................................................................ 78

                                                                                    ii
4.6.5.      Max メソッドと Min メソッドと Average メソッド ............................................................................. 79

  4.6.6.      MaxBy メソッドと MinBy メソッド ...................................................................................................... 82

  4.6.7.      Count メソッドと LongCount メソッド ................................................................................................ 83

  4.6.8.      Any メソッド .......................................................................................................................................... 84

  4.6.9.      All メソッド ............................................................................................................................................ 85

  4.6.10.     Aggregate メソッド ................................................................................................................................ 86

  4.6.11.     Scan メソッド ......................................................................................................................................... 91

  4.6.12.     GroupBy メソッド .................................................................................................................................. 93

  4.6.13.     GroupByUntil メソッド ......................................................................................................................... 95

4.7.    IOBSERVABLE<T>から IENUMERABLE<T>への変換メソッド ....................................................................... 99

  4.7.1.      ToEnumerable メソッド ........................................................................................................................ 99

  4.7.2.      Latest メソッド .................................................................................................................................... 101

  4.7.3.      MostRecent メソッド ........................................................................................................................... 104

  4.7.4.      Next メソッド ....................................................................................................................................... 106

4.8.    TOEVENT メソッド........................................................................................................................................ 108

4.9.    重複を排除するメソッド ............................................................................................................................... 109

  4.9.1.      Distinct メソッド .................................................................................................................................. 109

  4.9.2.      Distinct メソッドのオーバーロード ..................................................................................................... 110

  4.9.3.      DistinctUntilChanged メソッド .......................................................................................................... 113

4.10.   BUFFER メソッドと WINDOW メソッド ........................................................................................................ 114

  4.10.1.     数でまとめる Buffer メソッドのオーバーロード ................................................................................. 114

  4.10.2.     時間でまとめる Buffer メソッドのオーバーロード ............................................................................. 118

  4.10.3.     任意のタイミングで値をまとめる Buffer メソッドのオーバーロード ................................................ 121

  4.10.4.     時間と数でまとめる Buffer メソッドのオーバーロード ...................................................................... 125

  4.10.5.     Window メソッド.................................................................................................................................. 127

4.11.   発行された値にたいして時間でフゖルタ・操作するメソッド ..................................................................... 130

  4.11.1.     Sample メソッド ................................................................................................................................... 130

  4.11.2.     Throttle メソッド ................................................................................................................................. 133

  4.11.3.     Delay メソッド ..................................................................................................................................... 135

  4.11.4.     Timeout メソッド ................................................................................................................................. 136

4.12.   時間に関する情報を付与する拡張メソッド .................................................................................................. 138


                                                                             iii
4.12.1.      Timestamp メソッド ............................................................................................................................ 139

       4.12.2.      TimeInterval メソッド ......................................................................................................................... 140

     4.13.   型変換を行う拡張メソッド ........................................................................................................................... 141

       4.13.1.      Cast メソッド ....................................................................................................................................... 141

       4.13.2.      OfType メソッド ................................................................................................................................... 142

     4.14.   COLD から HOT へ変換する拡張メソッド ..................................................................................................... 143

       4.14.1.      Publish メソッド .................................................................................................................................. 143

       4.14.2.      RefCount メソッド ............................................................................................................................... 148

       4.14.3.      引数を受け取る Publish メソッドのオーバーロード ........................................................................... 151

       4.14.4.      PublishLast メソッド ........................................................................................................................... 152

       4.14.5.      Replay メソッド.................................................................................................................................... 153

       4.14.6.      Multicast メソッド ............................................................................................................................... 155

5.     SUBJECT 系クラス ........................................................................................................................................ 159

     5.1.    SUBJECT<T>クラス ...................................................................................................................................... 159

     5.2.    BEHAVIORSUBJECT<T>クラス...................................................................................................................... 161

     5.3.    ASYNCSUBJECT<T>クラス ........................................................................................................................... 162

     5.4.    REPLAYSUBJECT<T>クラス .......................................................................................................................... 164

6.     IOBSERVABLE の合成 .................................................................................................................................. 165

     6.1.    MERGE メソッド ........................................................................................................................................... 165

     6.2.    SELECTMANY メソッド ................................................................................................................................. 169

     6.3.    SWITCH メソッド........................................................................................................................................... 172

     6.4.    CONCAT メソッド .......................................................................................................................................... 176

     6.5.    ZIP メソッド .................................................................................................................................................. 178

     6.6.    AMB メソッド ................................................................................................................................................ 179

     6.7.    COMBINELATEST メソッド ............................................................................................................................ 180

     6.8.    STARTWITH メソッド .................................................................................................................................... 182

     6.9.    JOIN メソッド ............................................................................................................................................... 183

     6.10.   GROUPJOIN メソッド .................................................................................................................................... 186

     6.11.   WHEN メソッド ............................................................................................................................................. 189

       6.11.1.      Plan<TResult>クラスの作成 ............................................................................................................... 189


                                                                                   iv
6.11.2.       When メソッドの使用例 ....................................................................................................................... 190

       6.11.3.       まとめ .................................................................................................................................................... 193

7.     SCHEDULER ................................................................................................................................................ 193

     7.1.     実行場所の切り替え ...................................................................................................................................... 194

     7.2.     IOBSERVABLE<T>生成時の SCHEDULER の指定方法 ................................................................................... 195

       7.2.1.        デフォルトの Scheduler ....................................................................................................................... 197

     7.3.     SCHEDULER の切り替え ................................................................................................................................ 197

       7.3.1.        ObserveOn メソッド ............................................................................................................................ 197

       7.3.2.        ObserveOn の使用用途 ......................................................................................................................... 198

     7.4.     時間を制御する SCHEDULER ......................................................................................................................... 199

       7.4.1.        HistoricalScheduler クラス ................................................................................................................. 199

8.     応用編 ............................................................................................................................................................. 200

     8.1.     センサー監視 ................................................................................................................................................. 200

9.     参考サイト ...................................................................................................................................................... 203




                                                                                      v
1. はじめに

     ここでは、Reactive Extensions(下記リンク)の著者自身の理解を深めるために著者自身の
     Reactive Extensions の理解している内容を記載します。
     Dev Lab Reactive Extensions ホームページ

1.1. 前提環境

     ここでは、下記の環境を前提に説明を行います。

         Visual Studio 2010 SP1 Ultimate
         .NET Framework 4

         Reactive Extensions 1.0.*

     Visual Studio は、Visual C# 2010 SP1 Express Edition でも動作可能です。

1.2. 対象読者

     Reactive Extensions によるプログラミングに興味がある方。

1.3. 謝辞

     本ドキュメントのもとになった著者の Blog エントリの記事に対してコメント等で指摘していただ
     いた方々に感謝いたします。特に@neuecc さんには、サ゗トの情報や私の理解不足による誤った
     記載など丁寧に対応していただきとても感謝しています。




                                            1
2. Reactive Extensions とは

     Reactive Extensions は、公式ページに下記のように説明があります。
      The Reactive Extensions (Rx)...
      ...is a library to compose asynchronous and event-based programs using
      observable collections and LINQ-style query operators.

     私の拙い英語力で和訳を行うと「Reactive Extensions は、監視可能なコレクションと LINQ スタ
     ゗ルのオペレーションを使用して非同期と゗ベントベースのプログラムを合成するラ゗ブラリで
     す。」となります。

     個人的な解釈としては、Reactive Extensions とは何かしらの値を 0 回以上通知するもの(C#の
     event や非同期処理やタ゗マーなど etc…)を統一的なプログラミングモデルで扱えるようにした
     ものです。   そして、この統一的なプログラミングモデルを提供するための要となる゗ンターフェー
     スが System 名前空間の下にある IObservable<T>と IObserver<T>です。

2.1. Observer パターン

     Observer と Observable という名前からもわかる通り、この゗ンターフェースはデザ゗ンパター
     ンの Observer パターンのための機構を提供します。IObserver<T>゗ンターフェースが、
     IObservable<T>゗ンターフェースの発行する゗ベントを監視するという構造になります。
     IObserver<T>゗ンターフェースには下記の 3 つのメソッドが定義されています。

     1. void OnNext(T value)メソッド
        IObservable<T>から発生した通知を受け取って処理を行います

     2. void OnError(Exception ex)メソッド
        IObservable<T>で発生した例外を受け取って処理を行います。

     3. void OnCompleted()メソッド
        IObservable<T>からの通知が終了した時の処理を行います。

     対になる IObservable<T>には下記の 1 つのメソッドが定義されています。

     1. IDisposable Subscribe(IObserver<T> observer)メソッド
        引数で受け取った Observer に゗ベントの通知を行うようにします。戻り値の IDisposable の
        Dispose メソッドを呼び出すと通知を取り消します。

     Reactive Extensions は、この Observer パターンを土台にして構築されたラ゗ブラリになります。

2.2. Reactive Extensions で提供されている機能

     Reactive Extensions は、この IObservable<T>と IObserver<T>をベースに下記のような機能
     を提供しています。
     1. IObservable<T>のフゔクトリメソッド
        Reactive Extensions には IObservable<T>を返すフゔクトリメソッドが多数用意されてい
        ます。 .NET の標準の゗ベントから IObservable<T>を生成するメソッドや、      非同期呼び出し、


                                        2
タ゗マー、シーケンス、特定のルールで生成される値の集合 etc…さまざまなものが提供され
         ています。

    2. IObservable<T>の拡張メソッド
       IObservable<T>と IObserver<T>だけでは゗ベントの発行と購読の関係にしかなりません。
       Reactive Extensions では、ここに LINQ スタ゗ルの拡張メソッドを提供することで
       IObservable<T>から発行された値をフゖルタリングしたり、       発行された値を元に別の処理を
       行ったり、発行された値の変換を行ったりすることが出来ます。

    IObserver<T>生成へのショートカット
    IObserver<T>を実装しなくても、ラムダ式から IObserver<T>を内部的に生成してくれるため
    実際に Reactive Extensions を使用するときには IObserver<T>゗ンターフェースを実装するケ
    ースは、ほとんどありません。

    3. 柔軟なスレッドの切り替え機能
       IObservable<T>から発行された値に対する処理を何処のスレッドで実行するのか柔軟に切
       り替える機能が提供されています。このためバックグラウンドで時間のかかる処理を行い、UI
       スレッドに切り替えて画面の更新を行うといった処理が簡単に行えるようになります。

    以上が、Reactive Extensions で提供されている機能の全体像になります。次からは、Reactive
    Extensions の基本となる IObservable<T>゗ンターフェースと IObserver<T>゗ンターフェー
    スを見ていこうと思います。

2.3. IObservalbe<T>インターフェースと IObserver<T>インターフェース

    ここでは、Reactive Extensions の機能の要となる IObservable<T>と IObserver<T>を実装し
    て、その動作を確認します。まずは、Observer パターンでの監視役となる IObserver<T>から実
    装を行います。IObserver<T>゗ンターフェースは、先に示したように OnNext と OnError と
    OnCompleted の3つのメソッドからなります。この3種類のメソッド内に IObservable<T>か
    ら通知された値を受け取った時の処理を行います。ここでは、IObservable<T>から通知された
    値を単純にコンソールに出力するものを作成します。
     namespace IObservableIObserverImpl

     {

         using System;



         // 監視する人

         class PrintObserver : IObserver<int>

         {

             // 監視対象から通知が来たときの処理

             public void OnNext(int value)

             {

                 Console.WriteLine("OnNext({0}) called.", value);

             }



                                                  3
// 完了通知が来たときの処理

         public void OnCompleted()

         {

             Console.WriteLine("OnCompleted called.");

         }



         // エラー通知が来たときの処理

         public void OnError(Exception error)

         {

             Console.WriteLine("OnError({0}) called.", error.Message);

         }

     }

 }

単純に、OnNext と OnCompleted と OnError で標準出力に値を出力しています。次に
IObservable<T>を実装したコードを示します。
 namespace IObservableIObserverImpl

 {

     using System;

     using System.Collections.Generic;



     /// <summary>

     /// 監視されるクラス

     /// </summary>

     class NumberObservable : IObservable<int>

     {

         // 自分を監視してる人を管理するリスト

         private List<IObserver<int>> observers = new List<IObserver<int>>();



         // 自分を監視してる人に通知を行う

         // 0 を渡したらエラー通知

         public void Execute(int value)

         {

             if (value == 0)

             {

                 foreach (var obs in observers)

                 {

                     obs.OnError(new Exception("value is 0"));

                                                4
}



        // エラーが起きたので処理は終了

        this.observers.Clear();

        return;

    }



    foreach (var obs in observers)

    {

        obs.OnNext(value);

    }

}



// 完了通知

public void Completed()

{

    foreach (var obs in observers)

    {

        obs.OnCompleted();

    }

    // 完了したので監視してる人たちをクリゕ

    this.observers.Clear();

}



// 監視してる人を追加する。

// 戻り値の IDisposable を Dispose すると監視から外れる。

public IDisposable Subscribe(IObserver<int> observer)

{

    this.observers.Add(observer);

    return new RemoveListDisposable(observers, observer);

}



// Dispose が呼ばれたら observer を監視対象から削除する

private class RemoveListDisposable : IDisposable

{

    private List<IObserver<int>> observers = new List<IObserver<int>>();

    private IObserver<int> observer;

                                       5
public RemoveListDisposable(List<IObserver<int>> observers, IObserver<int> observer)

             {

                 this.observers = observers;

                 this.observer = observer;

             }



             public void Dispose()

             {

                 if (this.observers == null)

                 {

                     return;

                 }



                 if (observers.IndexOf(observer) != -1)

                 {

                     this.observers.Remove(observer);

                 }



                 this.observers = null;

                 this.observer = null;

             }

         }

     }

 }



IObservable<T>の実装は IObserver<T>に比べて複雑になっています。これは、
IObservable<T>゗ンターフェースが IObserver<T>を自分自身の監視役として登録する
Subscribe メソッドしか提供していないため、その他の監視役の IObserver<T>の保持や、
Subscribe メソッドの戻り値の IDosposable の Dispose を呼び出したときの監視役解除の処理を
作りこんでいるためです。どちらも一般的な C#によるプログラミングの範囲の内容になるので詳
細は割愛します。      最期に、この PrintObserver クラスと NumberObservable クラスを使ったサン
プルプログラムを以下に示します。
 namespace IObservableIObserverImpl

 {

     using System;



     class Program

                                               6
{

              static void Main(string[] args)

              {

                  // 監視される人を作成

                  var source = new NumberObservable();

                  // 監視役を2つ登録

                  var sbscriber1 = source.Subscribe(new PrintObserver());

                  var sbscriber2 = source.Subscribe(new PrintObserver());



                  // 監視される人の処理を実行

                  Console.WriteLine("## Execute(1)");

                  source.Execute(1);

                  // 片方を監視する人から解雇

                  Console.WriteLine("## Dispose");

                  sbscriber2.Dispose();

                  // 再度処理を実行

                  Console.WriteLine("## Execute(2)");

                  source.Execute(2);

                  // エラーを起こしてみる

                  Console.WriteLine("## Execute(0)");

                  source.Execute(0);

                  // 完了通知

                  // もう 1 つ監視役を追加して完了通知を行う

                  var sbscriber3 = source.Subscribe(new PrintObserver());

                  Console.WriteLine("## Completed");

                  source.Completed();

              }

          }

}



    上記のプログラムは、NumberObservable 型の変数 source に PrintObserver を 2 つ登録してい
    ます。その状態で Execute メソッドを呼んだり Dispose を読んだりエラーを起こしたりして出力
    を確認しています。このプログラムを動かすと下記のような結果になります。
    ## Execute(1)

    OnNext(1) called.

    OnNext(1) called.

    ## Dispose

                                                  7
## Execute(2)

     OnNext(2) called.

     ## Execute(0)

     OnError(value is 0) called.

     ## Completed

     OnCompleted called.

     最初の Execute では、PrintObserver を 2 つ登録しているので 2 回 OnNext が呼ばれていること
     が確認出来ます。       次に片方を Dispose した後では Execute を読んでも 1 回しか OnNext が呼ばれ
     ません。   Execute メソッドの引数に 0 を渡してエラーを起こした場合と処理を完了させたときも、
     PrintObserver に処理が伝わっていることが確認できます。

2.4. Reactive Extensions の機能を使った書き直し

     ここまで書いてきたプログラムは、Reactive Extensions の説明というよりは IObservable<T>
     ゗ンターフェースと IObserver<T>゗ンターフェースを実装して使用しただけの Observer パタ
     ーンの1実装例です。ここでは、このプログラムを Reactive Extensions が提供する便利な拡張
     メソッドやクラスを使って書き換えを行います。
     Reactive Extensions を使ったプログラムでは、頻繁に IObservable<T>゗ンターフェースの
     Subscribe メソッドを使用して通知に対するゕクションを設定します。この時、実行したい処理の
     単位でクラスを作成するのは現実的ではありません。そのため、Reactive Extensions では
     System.ObservableExtensions クラスで IObservable<T>゗ンターフェースの拡張メソッドを
     定義しています。主な拡張メソッドは下記の 3 つになります。どれもデリゲートを受け取るタ゗
     プになります。

          void Subscribe<T>(this IObservable<T> source, Action<T> onNext)

          void Subscribe<T>( this IObservable<T> source, Action<T> onNext, Action
           onCompleted)
          void Subscribe<T>( this IObservable<T> source, Action<T> onNext,
           Action<Exception> onError, Action onCompleted)

      この拡張メソッドを使うことでデリゲートで IObserver<T>゗ンターフェースの OnNext メソッ
     ドと OnError メソッドと OnCompleted メソッドを指定するだけで内部で IObserver<T>を継承
     したクラスを作成して IObservable<T>゗ンターフェースの Subscribe(IObserver<T>)メソッ
     ドへ渡してくれます。このため、Reactive Extensions を使う上では IObserver<T>゗ンターフ
     ェースを実装することは、ほぼ無くなります。            (私は今まで実際の処理を書いていて実装したこと
     は有りません)上記の拡張メソッドを使うためには Reactive Extensions をプロジェクトの参照
     に追加します。    Nuget で Rx-Main という名前のパッケージをプロジェクトに追加します。        (Express
     Edition の方は nuget コマンドラ゗ンを゗ンストールして nuget install rx-main でダウンロード
     されるので手動で参照に追加してください)そして、           Main のプログラムを下記のように変更します。
         // 監視される人を作成

         var source = new NumberObservable();

         // 2 つ監視役を登録

                                                8
var subscriber1 = source.Subscribe(

   // OnNext

   value => Console.WriteLine("OnNext({0}) called.", value),

   // OnError

   ex => Console.WriteLine("OnError({0}) called.", ex.Message),

   // OnCompleted

   () => Console.WriteLine("OnCompleted() called."));

var subscriber2 = source.Subscribe(

   // OnNext

   value => Console.WriteLine("OnNext({0}) called.", value),

   // OnError

   ex => Console.WriteLine("OnError({0}) called.", ex.Message),

   // OnCompleted

   () => Console.WriteLine("OnCompleted() called."));



// 監視される人の処理を実行

Console.WriteLine("## Execute(1)");

source.Execute(1);

// 1 つを監視する人から解雇

Console.WriteLine("## Dispose");

subscriber2.Dispose();

// 再度処理を実行

Console.WriteLine("## Execute(2)");

source.Execute(2);

// エラーを起こしてみる

Console.WriteLine("## Execute(0)");

source.Execute(0);

// もう 1 つ監視役を追加して完了通知を行う

var sbscriber3 = source.Subscribe(

   // OnNext

   value => Console.WriteLine("OnNext({0}) called.", value),

   // OnError

   ex => Console.WriteLine("OnError({0}) called.", ex.Message),

   // OnCompleted

   () => Console.WriteLine("OnCompleted() called."));

Console.WriteLine("## Completed");

source.Completed();

                                           9
引数を 3 つ受け取るタ゗プの Subscribe 拡張メソッドを使用しているため PrintObserver クラス
は不要になります。今回の例では、同じ処理を何度も Subscribe しているのでメソッドとして切
り出すなりしたほうがコードの重複が無くなりますが、       サンプルとしての見通しのためにあえて 1
メソッド内に重複コードを書いています。

次に IObservable<T>の実装クラスですが、これも IObservable<T>を実装したクラスが提供さ
れています。System.Reactive.Subjects.Subject<T>クラスがそれにあたります。このクラスは
IObservable<T>゗ンターフェースと IObserver<T>゗ンターフェースの両方を実装していて
OnNext や OnError や OnCompleted などの IObserver<T>゗ンターフェースで提供されている
メソッドを呼び出すと IObservable<T>゗ンターフェースの Subscribe メソッドで監視対象とし
て追加されている IObserver<T>に処理を通知します。このクラスをラップする形で使うと簡単
に IObservable<T>゗ンターフェースを実装することが出来ます。
 namespace UseSubscribeMethod

 {

     using System;

     using System.Reactive.Subjects;



     class NumberObservable : IObservable<int>

     {

         // IObservable<T>と IObserver<T>の両方を兼ねるクラス

         private Subject<int> source = new Subject<int>();



         // 自分を監視してる人に通知を行う

         // 0 を渡したらエラー通知

         public void Execute(int value)

         {

             if (value == 0)

             {

                 this.source.OnError(new Exception("value is 0"));

                 // エラー状態じゃないまっさらな Subject を再作成

                 this.source = new Subject<int>();

                 return;

             }



             this.source.OnNext(value);

         }



         // 完了通知

         public void Completed()


                                             10
{

                 this.source.OnCompleted();

             }



             // 監視してる人を追加する。

             // 戻り値の IDisposable を Dispose すると監視から外れる。

             public IDisposable Subscribe(IObserver<int> observer)

             {

                 return this.source.Subscribe(observer);

             }

         }

     }

    これで、初期のプログラムと同じ動作を実装出来ました。ただし、Reactive Extensions を普通に
    使っている範囲では、    Subject<T>クラスは使用することは少ないです。本来は、IObservable<T>
    を実装したクラスを生成するためのフゔクトリメソッドが用意されているので、         そちらを利用する
    ことのほうが多いです。     しかし、   動作確認をするためには自分で値の発行などが細かく制御できる
    Subject<T>クラスを、これから先のサンプルで使用するために紹介しました。



3. IObservable<T>のファクトリメソッド

    ここでは、Reactive Extensions で提供される IObservable<T>を作成するフゔクトリメソッド
    を紹介します。通常の Reactive Extensions を使ったプログラミングでは、提供されている様々
    なフゔクトリメソッドから IObservable<T>を生成して使用します。そのため、どのような
    IObservable<T>の生成方法があるかを把握していることは Reactive Extensions を使う上でと
    ても重要な要素になります。フゔクトリメソッドは基本的に System.Reactive.Linq.Observable
    クラスの static メソッドとして提供されています。メソッドの一覧は下記の MSDN のドキュメン
    トを参照してください。


    MSDN Observable クラス
    http://msdn.microsoft.com/en-us/library/system.reactive.linq.observable(v=VS.103).as
    px

3.1. 基本的なファクトリメソッドの使用

    ここでは、数多くある Observable クラスのフゔクトリメソッドから基本的なものをいくつか紹介
    します。




                                                 11
3.2. 指定された値を返す IObservable<T>を返すファクトリメソッド

3.2.1. Observable.Return メソッド

      まず、一番動作を理解しやすい指定した値を通知する IObservable<T>を作成するメソッドから
      使用します。最初に紹介するメソッドは Return メソッドになります。これは引数に指定した値を
      通知する IObservable<T>を作成します。コード例を以下に示します。
        // 10 を発行する IObservable<int>を作成する

        var source = Observable.Return(10);

        // 購読

        var subscription = source.Subscribe(

            i => Console.WriteLine("OnNext({0})", i),

            ex => Console.WriteLine("OnError({0})", ex.Message),

            () => Console.WriteLine("Completed()"));

        // 購読の停止(この場合意味はない)

        subscription.Dispose();

      コメントにあるように、このコードは 10 という値を発行する IObservable<int>を作成していま
      す。実行結果は下記のようになります。
      OnNext(10)

      Completed()

      Return で作成した IObservable<T>は値を 1 つ発行すると、それ以降発行する値が無いため終了
      状態になります。そのため Subscribe をすると実行結果のように OnNext の後に Completed が
      呼ばれます。また、ここでは示していませんが 2 回 Subscribe を行うと値の発行と終了の通知を
      再び行います。上記のコード例で言うと、2 回目の Subscribe の呼び出しでも、OnNext(10)と
      Completed()が表示されます。

3.2.2. Observable.Repeat メソッド

      次は、同じ値を指定した回数発行する IObservable<T>を返すメソッドになります。コード例を
      下記に示します。
        // 2 を 5 回発行する IObservable<int>を作成する

        var source = Observable.Repeat(2, 5);

        // 購読

        var subscription = source.Subscribe(

            i => Console.WriteLine("OnNext({0})", i),

            ex => Console.WriteLine("OnError({0})", ex.Message),

            () => Console.WriteLine("Completed()"));

        // 購読停止(この場合意味はない)

        subscription.Dispose();

                                                    12
これを実行すると下記のようになります。
      OnNext(2)

      OnNext(2)

      OnNext(2)

      OnNext(2)

      OnNext(2)

      Completed()

      同じ値をひたすら発行しているのがわかります。

3.2.3. Observable.Range メソッド

      このメソッドは、指定した値から 1 ずつカウントゕップした値を指定した個数だけ返します。コ
      ード例を下記に示します。
        // 1 から始まる値を 10 個発行する IObservable<int>を作成する

        var source = Observable.Range(1, 10);

        // 購読

        var subscription = source.Subscribe(

            i => Console.WriteLine("OnNext({0})", i),

            ex => Console.WriteLine("OnError({0})", ex.Message),

            () => Console.WriteLine("Completed()"));

        // 購読停止(この場合意味はない)

        subscription.Dispose();

      1 からカウントゕップする値を 10 個発行するので 1~10 の値を発行する IObservable<int>を作
      成しています。実行例を下記に示します。
      OnNext(1)

      OnNext(2)

      OnNext(3)

      OnNext(4)

      OnNext(5)

      OnNext(6)

      OnNext(7)

      OnNext(8)

      OnNext(9)

      OnNext(10)

      Completed()




                                                    13
3.2.3.1. IObservable<T>の拡張メソッドの Repeat

      ここまでは Observable クラスに定義された IObservable<T>を返すメソッドを使ってきました
      が、ここで少し横道に逸れて IObservable<T>の拡張メソッドとして定義された Repeat メソッ
      ドを紹介したいと思います。この拡張メソッドも Observable クラスに定義されています。これま
      でのメソッドとの違いは純粋な static メソッドではなく、IObservable<T>の拡張メソッドとし
      て定義されている点です。      この Repeat 拡張メソッドは、 IObservable<T>が発行する値を指定し
      た回数繰り返す IObservable<T>を作成します。Range メソッドと組み合わせて使用した例を下
      記に示します。
        // 1 から始まる値を 3 個発行する IObservable<int>を作成する

        var source = Observable.Range(1, 3);

        // そして、それを 3 回繰り返す IObservable<int>を作成する

        source = source.Repeat(3);

        // 購読

        var subscription = source.Subscribe(

            i => Console.WriteLine("OnNext({0})", i),

            ex => Console.WriteLine("OnError({0})", ex.Message),

            () => Console.WriteLine("Completed()"));

        // 購読停止(この場合意味はない)

        subscription.Dispose();

      実行結果は下記のようになります。1~3 の値が 3 回発行されているのがわかります。
      OnNext(1)

      OnNext(2)

      OnNext(3)

      OnNext(1)

      OnNext(2)

      OnNext(3)

      OnNext(1)

      OnNext(2)

      OnNext(3)

      Completed()


3.2.4. Observable.Generate メソッド

      次は、Generate メソッドです。このメソッドは for 文に近い使用感のメソッドになっています。
      第一引数で初期値状態、第二引数で継続の条件、第三引数で更新処理、第四引数で発行する値の生
      成を行う処理を渡します。    コードを見ていただくと゗メージがわきやすいと思うので下記にコード
      例を示します。
        // 初期値 0, 値が 10 より小さい間, 値は 1 ずつ゗ンクリメントして, 値を二乗したものを発行する


                                                    14
// IObservable<int>を作成する。

        // for (int i = 0; i < 10; i++) { yield return i * i; }のような゗メージ

        var source = Observable.Generate(0, i => i < 10, i => ++i, i => i * i);

        // 購読

        var subscription = source.Subscribe(

            i => Console.WriteLine("OnNext({0})", i),

            ex => Console.WriteLine("OnError({0})", ex.Message),

            () => Console.WriteLine("Completed()"));

        // 購読停止(この場合意味はない)

        subscription.Dispose();

      このコードを実行すると 0~9 までの値を二乗したものを発行する IObservable<int>が作成され
      ます。実行結果は下記のようになります。
      OnNext(0)

      OnNext(1)

      OnNext(4)

      OnNext(9)

      OnNext(16)

      OnNext(25)

      OnNext(36)

      OnNext(49)

      OnNext(64)

      OnNext(81)

      Completed()

      0~9 までの値を二乗した値が発行されているのが確認出来ます。

3.2.5. Observable.Defer メソッド

      次に紹介するメソッドは Defer メソッドです。このメソッドは IObservable<T>を直接返すラム
      ダ式を引数に渡します。Subscribe メソッドが呼ばれる度に、Defer メソッドが実行されて
      IObservable<T>が作成されます。コード例を以下に示します。
        // 1, 2, 3 と順番に値を発行して終了する IObservable<int>を生成する

        var source = Observable.Defer<int>(() =>

        {

            Console.WriteLine("# Defar method called.");

            // ReplaySubject<T>は Subject<T>の亜種で Subscribe されると

            // 今まで行われた操作を全てリプレ゗する。

            var s = new ReplaySubject<int>();

            s.OnNext(1);

                                                     15
s.OnNext(2);

        s.OnNext(3);

        s.OnCompleted();

        // AsObservable で IObservable<T>へ変換できる。

        return s.AsObservable();

  });

  // 購読(source は ReplaySubject で作っているので Defer メソッド内でした操作が再生される)

  var subscription1 = source.Subscribe(

        i => Console.WriteLine("OnNext({0})", i),

        ex => Console.WriteLine("OnError({0})", ex.Message),

        () => Console.WriteLine("Completed()"));

  var subscription2 = source.Subscribe(

        i => Console.WriteLine("OnNext({0})", i),

        ex => Console.WriteLine("OnError({0})", ex.Message),

        () => Console.WriteLine("Completed()"));

  // 購読停止(この場合意味はない)

  subscription1.Dispose();

  subscription2.Dispose();

実行結果は下記のようになります。2 回 Subscribe しているので 2 回 Defer メソッドが呼ばれて
いることが確認出来ます。
# Defar method called.

OnNext(1)

OnNext(2)

OnNext(3)

Completed()

# Defar method called.

OnNext(1)

OnNext(2)

OnNext(3)

Completed()

Defer メソッド内で使用している ReplaySubject<T>クラスは、コメント内にあるように
Subject<T>クラスの親戚のクラスです。   Subject<T>クラスが Subscribe される前の操作は通知
しないのに対して ReplaySubject<T>クラスは、Subscribe される前の操作も通知する点が異な
ります。試しに Defer メソッド内の ReplaySubject<T>を普通の Subject<T>に変更して実行す
ると下記のような結果になります。
# Defar method called.

Completed()


                                                16
# Defar method called.

      Completed()

      Defer メソッドで返された IObservable<int>は既に通知する値が無く完了した状態になってい
      るため、OnCompleted だけが実行されます。

3.2.6. Observable.Create メソッド

      次は、Create メソッドを紹介します。このメソッドは、引数の形が特殊で IObserver<T>を受け
      取って Action を返すラムダ式を引数に受け取ります。引数で受け取る IObserver<T>には
      OnNext や OnErrror や OnCompleted などの操作を行います。ここで行った操作に応じた値が
      Create メソッドの戻り値の IObservable<T>で発行される値になります。    最期に戻り値の Action
      ですが、これは Dispose された時に実行される処理になります。Create メソッド内でリソースや
      ゗ベントの購読などをしていた場合に解放する処理を行うと良いと思います。              では、コード例を下
      記に示します。
        // 1, 2, 3 と順番に値を発行して終了する IObservable<int>を生成する

        var source = Observable.Create<int>(observer =>

        {

              Console.WriteLine("# Create method called.");

              // 引数の IObserver<int>に対して On****メソッドを呼ぶ

              observer.OnNext(1);

              observer.OnNext(2);

              observer.OnNext(3);

              observer.OnCompleted();

              // Dispose が呼ばれた時の処理を返す。

              // リソースを確保していた場合は、ここで解放すると良い。

              return () => Console.WriteLine("Disposable action");

        });

        // 購読

        var subscription1 = source.Subscribe(

              i => Console.WriteLine("OnNext({0})", i),

              ex => Console.WriteLine("OnError({0})", ex.Message),

              () => Console.WriteLine("Completed()"));

        var subscription2 = source.Subscribe(

              i => Console.WriteLine("OnNext({0})", i),

              ex => Console.WriteLine("OnError({0})", ex.Message),

              () => Console.WriteLine("Completed()"));

        // 購読停止(この場合意味はない)

        Console.WriteLine("# Dispose method call.");

        subscription1.Dispose();

                                                       17
subscription2.Dispose();

      実行結果は、下記のようになります。
      ## CreateSample

      # Create method called.

      OnNext(1)

      OnNext(2)

      OnNext(3)

      Completed()

      Disposable action

      # Create method called.

      OnNext(1)

      OnNext(2)

      OnNext(3)

      Completed()

      Disposable action

      # Dispose method call.

      注意したいのは Disposable action の表示されているタ゗ミングです。通常の考えだと
      subscription1.Dispose();の呼び出しタ゗ミングで Disposable action と表示されるように思いま
      すが動作を確認すると Dispose メソッドを呼ぶ前に自動で呼び出されています。これは、
      Completed の後で、もう購読していても値が来ないため Dispose が自動で行われていることを示
      しています。     これまでのサンプルでも Dispose に特に意味がないと書いていたのはこのためです。

3.2.7. Observable.Throw メソッド

      一連の基本的な IObservable<T>を作成するメソッドの締めくくりとして最後に Throw メソッド
      を紹介します。これは引数に例外を渡します。      疑似的にエラーを起こしたいときに使う以外に使用
      方法が思いつきません。コード例を下記に示します。
        // エラーを発行するだけの IObservable<int>を生成

        var source = Observable.Throw<int>(new Exception("Error message"));

        // 購読

        var subscription = source.Subscribe(

            i => Console.WriteLine("OnNext({0})", i),

            ex => Console.WriteLine("OnError({0})", ex.Message),

            () => Console.WriteLine("Completed()"));

        // 購読停止(この場合意味はない)

        subscription.Dispose();

      実行結果は下記のようになります。OnError が呼ばれているのがわかります。
      OnError(Error message)

                                                    18
3.3. ここまでに紹介した IObservable<T>の動作

    ここまで紹介してきた IObservable<T>は、全て下記のような特徴があります。

    1. フゔクトリで発行する値を指定して IObservable<T>を作成する。

    2. Subscribe が呼び出されると以下のような動きをする

      1. 値を全て発行する

      2. 終わったら OnCompleted を呼ぶ
      3. 購読を解除する

    3. Subscribe が行われる度に 2 の動作を行う。

    この動作を表した図を以下に示します。




    上記の図では OnError と二度目の Subscribe について書いていませんが、  基本的に OnError の時
    には例外が IObserver<T>に通知されます。また、一度の Subscribe で IObservable<T>が空に
    なるように見えますがデータの流れを示すために空にしているだけで実際には再度 Subscribe を
    行うと値が発行されます。

3.4. リソースの確保を伴う IObservable<T>

    ここでは、IObservable<T>を取得する際にリソースの確保を行うケースに使用できるフゔクト
    リメソッドについて説明します。




                                 19
3.4.1. Observable.Uting メソッド

      Using メソッドは、   名前の通り using ブロックのようにリソースを確実に解放するために使用する
      メソッドになります。メソッドのシグネチャは、第一引数に Func<TResource>を渡して、リソ
      ースを確保するオブジェクトを作成する処理を指定します。TResource 型は IDisposable を実装
      している必要があります。      第二引数に、    Func<TResource, IObservable<TSource>>を渡して、
      リソースを使って IObservable<T>を取得する処理を指定します。実際には、外部リソースに依
      存するものを使用する場合のコード例が適しているのですが、ここでのサンプルは、ダミーの
      IDisposable を実装した下記のようなクラスを使用して動作確認を行います。
        // サンプルのダミーリソースクラス

        class SampleResource : IDisposable

        {

            // データを取得する

            public IObservable<string> GetData()

            {

                return Observable.Create<string>(o =>

                {

                      o.OnNext("one");

                      o.OnNext("two");

                      o.OnNext("three");

                      o.OnCompleted();

                      return Disposable.Empty;

                });

            }



            // 解放処理

            public void Dispose()

            {

                Console.WriteLine("Resource.Dispose called");

            }

        }

      このクラスを使用して Using メソッドの動作確認を行います。Using メソッドの使用例を下記に
      示します。
        // SampleResource(IDisposable を実装)を使用してデータを取得する

        var source = Observable.Using(

            () => new SampleResource(),

            sr => sr.GetData());

        // 購読

                                                    20
source.Subscribe(

            i => Console.WriteLine("OnNext({0})", i),

            ex => Console.WriteLine("OnError({0})", ex.Message),

            () => Console.WriteLine("Completed()"));

      Using メソッドで SampleResource クラスの作成と、SampleResource クラスを使って
      IObservable<T>を取得しています。このコードの実行結果を下記に示します。
      OnNext(one)

      OnNext(two)

      OnNext(three)

      Completed()

      Resource.Dispose called

      実行結果からもわかるように、最後に、SampleResource クラスの Dispose が呼ばれていること
      がわかります。

3.5. 時間と共に値を発行する IObservable<T>

      ここでは時間と共に値を発行する IObservable<T>を返すフゔクトリメソッドを使って動作を確
      認します。

3.5.1. 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();


                                                    21
// Observable が発行する値の購読を停止

  Console.WriteLine("dispose method call.");

  subscription.Dispose();

  // Dispose をすると値が発行されなくなる。

  Console.WriteLine("please enter key...");

  Console.ReadLine();

コメントにもある通り、          上記のコードは 3 秒後から 1 秒間隔で値を発行する IObservable<long>
を作成して Subscribe で購読しています。そして、Console.ReadLine で待機しています。暫く
待っていると OnNext が発行されます。適当なタ゗ミングで Enter キーを押すと
subscription.Dispose()が実行され、購読が解除されます。Dispose のあとは、OnNext が実行さ
れないことを確認できます。実行結果を下記に示します。
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...

Timer の実行゗メージを下図に示します。




                                               22
3.5.2. 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 が実行されたあとに数秒間待機し
      て購読が停止していることを確認しています。
                                                     23
3.5.3. Observable.Generate メソッド

      次は、3.2.4 でも使用した Generate メソッドを使用します。Generate メソッドには TimeSpan
      を受け取るオーバーロードがあり、これを使うことで指定した時間間隔で値を発行する
      IObservable<T>を作成できます。コード例を下記に示します。
        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)
                                                     24
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 メソッドの処理を途中から購読しなくなります。

3.6. Cold な IObservable<T>と Hot な IObservable<T>

     ここまでに紹介した IObservable<T>のフゔクトリメソッドは全て共通の特徴があります。それ
     は複数回 Subscribe すると、それぞれの IObserver<T>に IObservable<T>が個別に値を発行し
     ます。IObservable<T>の作り方にもよりますが、基本的には同じ値が発行されていきます。文
     章で説明するよりもコードの動作例で示します。
       // 1 秒間隔で値を発行する IObservable<long>を作成する

       var source = Observable.Timer(

           TimeSpan.FromSeconds(1),

           TimeSpan.FromSeconds(1));

       // 購読

       var subscription1 = source.Subscribe(

           i => Console.WriteLine("{0:yyyy/MM/dd HH:mm:ss.FFF} 1##OnNext({1})", DateTime.Now, i),

           ex => Console.WriteLine("1##OnError({0})", ex.Message),

                                                25
() => Console.WriteLine("1##Completed()"));



  // 3 秒後にもう一度購読

  Thread.Sleep(3000);

  // 購読

  var subscription2 = source.Subscribe(

      i => Console.WriteLine("{0:yyyy/MM/dd HH:mm:ss.FFF} 2##OnNext({1})", DateTime.Now, i),

      ex => Console.WriteLine("2##OnError({0})", ex.Message),

      () => Console.WriteLine("2##Completed()"));



  Console.ReadLine();

  subscription1.Dispose();

  subscription2.Dispose();

上記のコードは 1 秒間隔で値を発行する IObservable<long>を作成し、 回 Subscribe したあと
                                           1
に 3 秒待ってもう一度 Subscribe しています。この実行結果を下記に示します。
2011/11/07 23:05:01.883 1##OnNext(0)

2011/11/07 23:05:02.884 1##OnNext(1)

2011/11/07 23:05:03.879 1##OnNext(2)

2011/11/07 23:05:04.877 1##OnNext(3)

2011/11/07 23:05:04.893 2##OnNext(0)

2011/11/07 23:05:05.89 1##OnNext(4)

2011/11/07 23:05:05.894 2##OnNext(1)

2011/11/07 23:05:06.877 1##OnNext(5)

2011/11/07 23:05:06.892 2##OnNext(2)

2011/11/07 23:05:07.873 1##OnNext(6)

2011/11/07 23:05:07.894 2##OnNext(3)

最初に Subscribe した方には yyyy/MM/dd HH:mm:ss.FFF 1##OnNext(値)の形式で出力して
います。二番目に Subscribe した方には yyyy/MM/dd HH:mm:ss.FFF 2##OnNext(値)の形式
で出力しています。これを見ると、最初に Subscribe したものと二回目に Subscribe したもので
は、タ゗ムスタンプが微妙にずれていることから、               内部的には別のタ゗マーが割り当てられている
ことが見て取れます。また、発行される値も Subscribe した時点で 0 からカウントされていて最
初に Subscribe したものと二回目に Subscribe したものの間に関係性は全くありません。このよ
うに、Cold な Observable は「複数回 Subscribe した時に Observer 毎に独立した値を発行する」
という特徴があります。

では次に、Cold と対となるものとして Hot な IObservable<T>を見ていきます。Hot な
Observable の代表として.NET 組み込みの Observer パターンである゗ベントから
IObservable<T>を生成する Observable.FromEvent<TDelegate, TEventArgs>(…)というメ
ソッドがあります。このメソッドのシグネチャを下記に示します。

                                            26
public static IObservable<TEventArgs> FromEvent<TDelegate, TEventArgs>(

     // Action<TEventArgs>から゗ベントハンドラの形へと変換する処理

     // Action<TEventArgs>は Subscribe したときの OnNext の処理にあたる。

     Func<Action<TEventArgs>, TDelegate> conversion,

     // ゗ベントハンドラを登録する処理

     Action<TDelegate> addHandler,

     // ゗ベントハンドラの登録を解除する処理

     Action<TDelegate> removeHandler)

今まで出てきたもののなかではかなり異質の引数ですが゗ベントハンドラの形にあったデリゲー
トを作成してハンドラの登録処理と削除処理を渡します。あとは IObservable<TEventArgs>を
Subscribe したタ゗ミングや Dispose したタ゗ミングで適切に゗ベントの登録・登録解除が行わ
れます。   自前でやると゗ベントハンドラの登録解除は忘れがちな処理なので地味に有りがたい機能
です。コード例を下記に示します。
 // 1 秒間隔で値を発行する Timer

 var timer = new System.Timers.Timer(1000);

 var source = Observable.FromEvent<ElapsedEventHandler, ElapsedEventArgs>(

     h => (s, e) => h(e),

     h => timer.Elapsed += h,

     h => timer.Elapsed -= h);

 // タ゗マー開始

 timer.Start();



 // 購読

 var subscription1 = source.Subscribe(

    e => Console.WriteLine("{0:yyyy/MM/dd HH:mm:ss.FFF} 1##OnNext({1:yyyy/MM/dd
 HH:mm:ss.FFF})",DateTime.Now, e.SignalTime),

     ex => Console.WriteLine("1##OnError({0})", ex.Message),

     () => Console.WriteLine("1##Completed()"));



 // 3 秒後にもう一度購読

 Thread.Sleep(3000);

 // 購読

 var subscription2 = source.Subscribe(

    e => Console.WriteLine("{0:yyyy/MM/dd HH:mm:ss.FFF} 2##OnNext({1:yyyy/MM/dd
 HH:mm:ss.FFF})",DateTime.Now, e.SignalTime),

     ex => Console.WriteLine("2##OnError({0})", ex.Message),

     () => Console.WriteLine("2##Completed()"));



                                           27
Console.ReadLine();

        subscription1.Dispose();

        subscription2.Dispose();

        timer.Stop();

      Cold な Observable で示した処理と基本的には同じ処理を行っています。実行結果を下記に示し
      ます。
      2011/11/07 23:37:41.146 1##OnNext(2011/11/07 23:37:41.146)

      2011/11/07 23:37:42.16 1##OnNext(2011/11/07 23:37:42.16)

      2011/11/07 23:37:43.174 1##OnNext(2011/11/07 23:37:43.174) ← ここと

      2011/11/07 23:37:43.174 2##OnNext(2011/11/07 23:37:43.174) ← ここ 以下 2 つずつ同じ値が表示されてい
      る

      2011/11/07 23:37:44.188 1##OnNext(2011/11/07 23:37:44.188)

      2011/11/07 23:37:44.188 2##OnNext(2011/11/07 23:37:44.188)

      2011/11/07 23:37:45.202 1##OnNext(2011/11/07 23:37:45.202)

      2011/11/07 23:37:45.202 2##OnNext(2011/11/07 23:37:45.202)

      2011/11/07 23:37:46.216 1##OnNext(2011/11/07 23:37:46.216)

      2011/11/07 23:37:46.216 2##OnNext(2011/11/07 23:37:46.216)

      上記の結果で興味深い点は、最初に Subscribe したものと、二番目に Subscribe したものの出力
      結果のタ゗ムスタンプと、OnNext に渡ってきている値が同じという点です。

      つまり、Hot な IObservable<T>とは Cold な IObservable<T>と違って「複数回 Subscribe し
      たときに、全ての Observer に同じタ゗ミングで同じ値を発行するもの」ということになります。

3.6.1. Observable.FromEvent メソッド

      では、Hot な IObservable<T>を作成するメソッドのトップバッターとして先ほど登場した
      FromEvent メソッドを紹介します。FromEvent メソッドのシグネチャは既に示したので、より
      詳しく動作を確認するためのコードを下記に示します。
        // ゗ベントを発行するクラス

        var eventSource = new EventSource();

        var source = Observable.FromEvent<EventHandler, EventArgs>(

            h => (s, e) => h(e),

            // 普通は h => eventSource.Raised += h だけでいい

            h =>

            {

                 Console.WriteLine("add handler");

                 eventSource.Raised += h;

            },

            // 普通は h => eventSource.Raised -= h だけでいい


                                                     28
h =>

     {

           Console.WriteLine("remove handler");

           eventSource.Raised -= h;

     });



 // 2 回購読

 var subscription1 = source.Subscribe(

     i => Console.WriteLine("1##OnNext({0})", i),

     ex => Console.WriteLine("1##OnError({0})", ex.Message),

     () => Console.WriteLine("1##Completed()"));

 var subscription2 = source.Subscribe(

     i => Console.WriteLine("2##OnNext({0})", i),

     ex => Console.WriteLine("2##OnError({0})", ex.Message),

     () => Console.WriteLine("2##Completed()"));



 // 2 回呼び出してみる

 // 合計 4 回の OnNext が呼ばれるはず

 eventSource.OnRaised();

 eventSource.OnRaised();



 // Observable が発行する値の購読を停止

 Console.WriteLine("dispose method call.");

 subscription1.Dispose();

 subscription2.Dispose();

この例で使用している EventSource クラスは、Raised という゗ベントと OnRaised という゗ベ
ントを発行するメソッドだけを持ったクラスで下記のように定義しています。
 // ゗ベント発行クラス

 class EventSource

 {

     public event EventHandler Raised;

     public void OnRaised()

     {

           var h = this.Raised;

           if (h != null)

           {

               h(this, EventArgs.Empty);

                                              29
}

              }

        }

      このコードの実行結果を下記に示します。
      add handler

      add handler

      1##OnNext(System.EventArgs)

      2##OnNext(System.EventArgs)

      1##OnNext(System.EventArgs)

      2##OnNext(System.EventArgs)

      dispose method call.

      remove handler

      remove handler

      FromEvent メソッドの゗ベントハンドラ登録処理と゗ベントハンドラの登録解除処理にログを出
      力するように仕込んだものが表示されています。     このことから、Dispose を呼ぶときちんと゗ベン
      トハンドラの登録解除が行われることがわかります。また、゗ベントが発行されたタ゗ミングで 2
      つ登録した Observer の両方に対して通知がいっていることも確認できます。

3.6.2. Observable.Start メソッド

      次に、簡単にバックグラウンドの処理を記述できる Start メソッドについて説明します。Start メ
      ソッドは Action か Func<T>を引数に受け取り IObservable<Unit>か IObservable<T>を返し
      ます。引数で受け取ったデリゲートの処理が終わると IObservable から結果が発行されます。コ
      ード例を下記に示します。
        // バックグラウンドで処理を開始

        var source = Observable.Start(() =>

        {

              Console.WriteLine("background task start.");

              Thread.Sleep(2000);

              Console.WriteLine("background task end.");

              return 1;

        });

        // 購読

        Console.WriteLine("subscribe1");

        var subscription1 = source.Subscribe(

              i => Console.WriteLine("1##OnNext({0})", i),

              ex => Console.WriteLine("1##OnError({0})", ex.Message),

              () => Console.WriteLine("1##Completed()"));


                                                      30
// 処理が確実に終わるように 5 秒待つ

  Console.WriteLine("sleep 5sec.");

  Thread.Sleep(5000);



  // Observable が発行する値の購読を停止

  Console.WriteLine("dispose method call.");

  subscription1.Dispose();



  // 購読

  Console.WriteLine("subscribe2");

  var subscription2 = source.Subscribe(

      i => Console.WriteLine("2##OnNext({0})", i),

      ex => Console.WriteLine("2##OnError({0})", ex.Message),

      () => Console.WriteLine("2##Completed()"));

  subscription2.Dispose();

このサンプルで特徴的なのが、      Start メソッド内の処理が 2 秒で終わるにも関わらず 5 秒スリープ
した後に Subscribe をしている点です。通常の感覚では、既に処理が完了して値が発行された後
なので Subscribe しても何も起きないと考えられます。しかし、Start メソッドの戻り値の
IObservable<T>は最後の処理結果をキャッシュしています。     そのため、Subscribe されるとキャ
ッシュしている値と OnCompleted を発行します。

この例の実行結果では、最初の Subscribe と二回目の Subscribe それぞれで、OnNext と
OnCompleted の処理が呼ばれます。実行結果を下記に示します。
subscribe1

sleep 5sec.                    ← ここで 5 秒スリープしている

background task start.

background task end.

1##OnNext(1)

1##Completed()

dispose method call.

subscribe2                     ← このタ゗ミングでは Start メソッドの処理は終了している

2##OnNext(1)                    ← OnNext と OnCompleted が通知される

2##Completed()

このことから、Start メソッドで作成する IObservable<T>は、Start メソッドが完了するまでは
Hot な Observable で処理が終了したあとは Cold な Observable になるという 2 面性をもつとい
う特徴があることが確認できます。



                                               31
3.6.3. Observable.ToAsync メソッド

      次は、ToAsync メソッドを紹介します。このメソッドも Start メソッドと同様に重たい処理をバ
      ックグラウンドでやるために使用できます。Start メソッドとの違いは ToAsync の戻り値にあら
      われています。シグネチャを下記に示します。
        public static Func<IObservable<T>> ToAsync<T>(Func<T> function)

      引数に重たいことをやる処理を渡して、戻り値が IObservable<T>を返すデリゲートになってい
      ます。この戻り値のデリゲートを呼び出すことで ToAsync の引数に渡した処理がはじめて実行さ
      れます。Start は、Start メソッドを呼び出した直後から処理が開始されましたが、ToAsync を使
      うと処理の開始のタ゗ミングを柔軟に制御できます。

      ここで示したメソッドのシグネチャは数十個あるオーバーロードの 1 つになります。ToAsync に
      はほかにも戻り値が無いケースや引数が大量にあるケースに備えて膨大な数のオーバーロードが
      あります。完全なオーバーロードのリストについては下記の MSDN のリフゔレンスを参照してく
      ださい。

      Observable.ToAsync Method :
      http://msdn.microsoft.com/en-us/library/system.reactive.linq.observable.toasync(v=VS.
      103).aspx
      コード例を下記に示します。
        // 戻り値は Func<IObservable<T>>

        var source = Observable.ToAsync(() =>

        {

              Console.WriteLine("background task start.");

              Thread.Sleep(2000);

              Console.WriteLine("background task end.");

              return 1;

        });



        // ToAsync はデリゲートを返すので Invoke() or ()をしないと処理が開始されない

        Console.WriteLine("source() call.");

        var invokedSource = source.Invoke();

        var subscription1 = invokedSource.Subscribe(

              i => Console.WriteLine("1##OnNext({0})", i),

              ex => Console.WriteLine("1##OnError({0})", ex.Message),

              () => Console.WriteLine("1##Completed()"));

        // 処理が確実に終わるように 5 秒待つ

        Console.WriteLine("sleep 5sec.");

        Thread.Sleep(5000);




                                                      32
// Observable が発行する値の購読を停止

        Console.WriteLine("dispose method call.");

        subscription1.Dispose();



        // 購読

        Console.WriteLine("subscribe2");

        var subscription2 = invokedSource.Subscribe(

             i => Console.WriteLine("2##OnNext({0})", i),

             ex => Console.WriteLine("2##OnError({0})", ex.Message),

             () => Console.WriteLine("2##Completed()"));

        subscription2.Dispose();

      ポ゗ントは、ToAsync の戻り値に対して Invoke をしているところです。ここで初めて ToAsync
      に渡した処理の実行がはじまります。実行結果を下記に示します。
      source() call.

      background task start.

      sleep 5sec.

      background task end.

      1##OnNext(1)

      1##Completed()

      dispose method call.

      subscribe2

      2##OnNext(1)

      2##Completed()

      ここでも Start メソッドの例と同じように ToAsync の処理が終わった後に Subscribe しているに
      も関わらず OnNext と OnCompleted が呼ばれていることがわかります。非同期で処理を行う
      IObservable<T>は全体的にこのような動きを行うので覚えておきましょう。

3.6.4. Observable.FromAsyncPattern メソッド

      これで、一連のフゔクトリメソッドの紹介は最後になります。    最後を飾るのは FromAsyncPattern
      メソッドです。このメソッドは名前が示す通り.NET Framework で使われている非同期呼び出し
      のパターンから IObservable<T>を作成します。
        // 重たい処理

        Func<int, int, int> asyncProcess = (x, y) =>

        {

             Console.WriteLine("process start.");

             Thread.Sleep(2000);

             Console.WriteLine("process end.");


                                                       33
return x + y;

};



// 因みに非同期呼び出しは普通に書くとこんな感じ

// asyncProcess.BeginInvoke(

//     10, 2,

//     ar =>

//     {

//          var ret = asyncProcess.EndInvoke(ar);

//          // do something

//     },

//     null);

var asyncPattern = Observable.FromAsyncPattern<int, int, int>(

     asyncProcess.BeginInvoke,

     asyncProcess.EndInvoke);



var source = asyncPattern(10, 2);



// 処理中に購読開始

Console.WriteLine("subscribe2");

var subscription1 = source.Subscribe(

     i => Console.WriteLine("1##OnNext({0})", i),

     ex => Console.WriteLine("1##OnError({0})", ex.Message),

     () => Console.WriteLine("1##Completed()"));



// 確実に処理が終わるように 5 秒待つ

Console.WriteLine("sleep 5sec");

Thread.Sleep(5000);

// Observable が発行する値の購読を停止

Console.WriteLine("dispose method call.");

subscription1.Dispose();



// 処理が完了したあとに購読

Console.WriteLine("subscribe2");

var subscription2 = source.Subscribe(

     i => Console.WriteLine("2##OnNext({0})", i),

     ex => Console.WriteLine("2##OnError({0})", ex.Message),

                                             34
() => Console.WriteLine("2##Completed()"));



       // 購読解除

       Console.WriteLine("dispose method call.");

       subscription2.Dispose();

     普通はコールバックで書く非同期呼び出しを IObservable<T>にラッピングします。このメソッ
     ドも ToAsync と同様に戻り値がデリゲートなので、デリゲートを呼び出すことで非同期処理が開
     始されます。実行結果を下記に示します。
     process start.

     subscribe2

     sleep 5sec

     process end.

     1##OnNext(12)

     1##Completed()

     dispose method call.

     subscribe2

     2##OnNext(12)

     2##Completed()

     dispose method call.

     ここでも、処理が終わった後に Subscribe をしても OnNext と OnCompleted が呼ばれているこ
     とがわかります。



4. IObservable の拡張メソッド

     ここまで IObservable<T>を作成するための様々なフゔクトリメソッドを見てきました。ここで
     は、視点を変えて IObservable<T>を作成したあとに使用できる IObservable<T>に定義された
     拡張メソッドを紹介します。

4.1. LINQ のメソッド

     IObservable<T>の拡張メソッドも、   ほとんどが System.Reactive.Linq.Observable クラスに定
     義されています。その中でも LINQ でお馴染みの Where や Select メソッドも含まれています。
     LINQ のメソッドは IObservable<T>が発行した値に対して Where でフゖルタリングしたり
     Select で変換したりできます。下図は、その゗メージを表しています。




                                                    35
下図は Where でフゖルタリングされた場合を表しています。Where でフゖルタリングされた場
合は Select や Subscribe まで処理はいきません。




実際にコードで動きを確認してみます。
 // 値を発行するための Subject

 var subject = new Subject<int>();

 // AsObservable で IObservable<T>に変換(ゕップキャストで Subject<T>に戻せない

 var source = subject.AsObservable();



 // 普通に Subscribe

 source.Subscribe(

    value => Console.WriteLine("1##OnNext({0})", value),

    ex => Console.WriteLine(ex.Message),

    () => Console.WriteLine("1##OnCompleted()"));



 // 奇数のみ通すようにフゖルタリングして

 source.Where(i => i % 2 == 1)

    // 文字列に加工して

    .Select(i => i + "は奇数です")

    // 表示する
                                           36
.Subscribe(

        value => Console.WriteLine("2##OnNext({0})", value),

        ex => Console.WriteLine(ex.Message),

        () => Console.WriteLine("2##OnCompleted()"));



 // 1~10 の値を subject に対して発行する

 Observable.Range(1, 10).ForEach(i => subject.OnNext(i));

 // 完了通知を行う

 subject.OnCompleted();

上記のコードでは、1~10 の値を Subject<T>を使って発行しています。Subject<T>は、
AsObservable メソッドで IObservable<T>に変換できます。AsObservable をしなくても
Subject<T>クラスは IObservable<T>を継承しているので差支えはないのですが、純粋な
IObservable<T>に、なんとなくしたかったのでこの例では変換しています。通常は、内部に
Subject<T>クラスを抱えたクラスが外部に IObservable<T>を公開するときに、ダウンキャス
トされても Subject<T>型に戻せない IObservable<T>を返すために使用します。
その他に、今回初登場のメソッドとして ForEach メソッドがあります。これは引数に渡された
Action<T>を、IObservable<T>から発行された値を引数に渡して使用します。平たく言うと for
ループです。ここでは 1~10 の値を Observable.Range で作成して ForEach で Subject<T>に
流し込んでいます。
今回の本題である拡張メソッドは Where メソッドと Select メソッドになります。Where メソッ
ドは引数で渡した Func<T, bool>が true を返す要素のみを通します。Select メソッドは引数で
渡した Func<T, U>で値を変換します。上記の例では奇数以外の値をフゖルタリングして「X は
奇数です」という文字列に変換して、Subscribe 内で標準出力に出力しています。動作の違いを見
るために、Where や Select を使用しないで Subscribe もしています。

このプログラムの実行結果を下記に示します。
1##OnNext(1)

2##OnNext(1 は奇数です)

1##OnNext(2)

1##OnNext(3)

2##OnNext(3 は奇数です)

1##OnNext(4)

1##OnNext(5)

2##OnNext(5 は奇数です)

1##OnNext(6)

1##OnNext(7)

2##OnNext(7 は奇数です)

1##OnNext(8)

1##OnNext(9)


                                            37
2##OnNext(9 は奇数です)

      1##OnNext(10)

      1##OnCompleted()

      2##OnCompleted()

      実行結果から、Where によるフゖルタリングが行われていることと、Select による変換が行われ
      ていることがわかると思います。

4.2. 単一の値を取得するメソッド

      ここでは、IObservable<T>のシーケンスから単一の値を取得するために利用するメソッドにつ
      いて説明します。

4.2.1. First メソッドと Last メソッド

      まず、最初の値を取得する First メソッドと、最後の値を取得する Last メソッドについて説明し
      ます。各メソッドのシグネチャは以下のようになります。
        // First メソッド

        public static TSource First<T>(

              this IObservable<T> source

        )



        // Last メソッド

        public static TSource Last<T>(

              this IObservable<T> source

        )

      どちらのメソッドも IObservable<T>から T の値を取得します。First メソッドのコード例を下記
      に示します。
        // Observable を作成前のタ゗ムスタンプを表示

        Console.WriteLine("Timestamp {0:yyyy/MM/dd HH:mm:ss.FFF}", DateTime.Now);

        var firstResult = Observable

            // 5 秒間隔で値を発行する

            .Interval(TimeSpan.FromSeconds(5))

            .Select(i => "value is " + i)

            // 最初の値を取得

            .First();

        // First の実行が終わった後のタ゗ムスタンプを表示

        Console.WriteLine("Timestamp {0:yyyy/MM/dd HH:mm:ss.FFF}", DateTime.Now);

        // 取得した値を表示

        Console.WriteLine("firstResult: {0}", firstResult);

                                                       38
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1
Reactive extensions入門v0.1

Contenu connexe

Tendances

Observableで非同期処理
Observableで非同期処理Observableで非同期処理
Observableで非同期処理torisoup
 
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法Yoshifumi Kawai
 
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方Yoshifumi Kawai
 
MVPパターンによる設計アプローチ「あなたのアプリ報連相できてますか」
MVPパターンによる設計アプローチ「あなたのアプリ報連相できてますか」MVPパターンによる設計アプローチ「あなたのアプリ報連相できてますか」
MVPパターンによる設計アプローチ「あなたのアプリ報連相できてますか」U-dai Yokoyama
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 TipsTakaaki Suzuki
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するYoshifumi Kawai
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14Ryo Suzuki
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」Takuto Wada
 
コールバックと戦う話
コールバックと戦う話コールバックと戦う話
コールバックと戦う話torisoup
 
.NET最先端技術によるハイパフォーマンスウェブアプリケーション
.NET最先端技術によるハイパフォーマンスウェブアプリケーション.NET最先端技術によるハイパフォーマンスウェブアプリケーション
.NET最先端技術によるハイパフォーマンスウェブアプリケーションYoshifumi Kawai
 
Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介torisoup
 
UniTask入門
UniTask入門UniTask入門
UniTask入門torisoup
 
若輩エンジニアから見たUniRxを利用したゲーム開発
若輩エンジニアから見たUniRxを利用したゲーム開発若輩エンジニアから見たUniRxを利用したゲーム開発
若輩エンジニアから見たUniRxを利用したゲーム開発Hirohito Morinaga
 
Reactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単にReactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単にYoshifumi Kawai
 
20190604 Containerized MagicOnion on kubernetes with Observability with New R...
20190604 Containerized MagicOnion on kubernetes with Observability with New R...20190604 Containerized MagicOnion on kubernetes with Observability with New R...
20190604 Containerized MagicOnion on kubernetes with Observability with New R...Takayoshi Tanaka
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪Takuto Wada
 
基礎線形代数講座
基礎線形代数講座基礎線形代数講座
基礎線形代数講座SEGADevTech
 
ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計Yoshinori Matsunobu
 
MagicOnion入門
MagicOnion入門MagicOnion入門
MagicOnion入門torisoup
 
UniRxことはじめ
UniRxことはじめUniRxことはじめ
UniRxことはじめShoichi Yasui
 

Tendances (20)

Observableで非同期処理
Observableで非同期処理Observableで非同期処理
Observableで非同期処理
 
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
 
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
 
MVPパターンによる設計アプローチ「あなたのアプリ報連相できてますか」
MVPパターンによる設計アプローチ「あなたのアプリ報連相できてますか」MVPパターンによる設計アプローチ「あなたのアプリ報連相できてますか」
MVPパターンによる設計アプローチ「あなたのアプリ報連相できてますか」
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
コールバックと戦う話
コールバックと戦う話コールバックと戦う話
コールバックと戦う話
 
.NET最先端技術によるハイパフォーマンスウェブアプリケーション
.NET最先端技術によるハイパフォーマンスウェブアプリケーション.NET最先端技術によるハイパフォーマンスウェブアプリケーション
.NET最先端技術によるハイパフォーマンスウェブアプリケーション
 
Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介
 
UniTask入門
UniTask入門UniTask入門
UniTask入門
 
若輩エンジニアから見たUniRxを利用したゲーム開発
若輩エンジニアから見たUniRxを利用したゲーム開発若輩エンジニアから見たUniRxを利用したゲーム開発
若輩エンジニアから見たUniRxを利用したゲーム開発
 
Reactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単にReactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単に
 
20190604 Containerized MagicOnion on kubernetes with Observability with New R...
20190604 Containerized MagicOnion on kubernetes with Observability with New R...20190604 Containerized MagicOnion on kubernetes with Observability with New R...
20190604 Containerized MagicOnion on kubernetes with Observability with New R...
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
基礎線形代数講座
基礎線形代数講座基礎線形代数講座
基礎線形代数講座
 
ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計
 
MagicOnion入門
MagicOnion入門MagicOnion入門
MagicOnion入門
 
UniRxことはじめ
UniRxことはじめUniRxことはじめ
UniRxことはじめ
 

En vedette

ゲーム開発とMVC
ゲーム開発とMVCゲーム開発とMVC
ゲーム開発とMVCTakashi Komada
 
ゲーム開発とデザインパターン
ゲーム開発とデザインパターンゲーム開発とデザインパターン
ゲーム開発とデザインパターンTakashi Komada
 
Sappo ro#6資料2 ー完全版ー
Sappo ro#6資料2 ー完全版ーSappo ro#6資料2 ー完全版ー
Sappo ro#6資料2 ー完全版ーWakana_kudo
 
UniRxでPUNを使いやすくする
UniRxでPUNを使いやすくするUniRxでPUNを使いやすくする
UniRxでPUNを使いやすくするtorisoup
 
ペッパソン東の陣 Microsoft 提供 API のご紹介
ペッパソン東の陣 Microsoft 提供 API のご紹介ペッパソン東の陣 Microsoft 提供 API のご紹介
ペッパソン東の陣 Microsoft 提供 API のご紹介一希 大田
 
4 Colors Othello’s Algorithm @仙台 IT 文化祭 2017
4 Colors Othello’s Algorithm @仙台 IT 文化祭 20174 Colors Othello’s Algorithm @仙台 IT 文化祭 2017
4 Colors Othello’s Algorithm @仙台 IT 文化祭 2017Takaaki Suzuki
 
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践Yoshifumi Kawai
 
The History of Reactive Extensions
The History of Reactive ExtensionsThe History of Reactive Extensions
The History of Reactive ExtensionsYoshifumi Kawai
 
Unity dojo amplifyshadereditor101_jpn-jp
Unity dojo amplifyshadereditor101_jpn-jpUnity dojo amplifyshadereditor101_jpn-jp
Unity dojo amplifyshadereditor101_jpn-jp小林 信行
 
Unity道場aseスペシャル補足資料
Unity道場aseスペシャル補足資料Unity道場aseスペシャル補足資料
Unity道場aseスペシャル補足資料小林 信行
 
UniRx - Reactive Extensions for Unity
UniRx - Reactive Extensions for UnityUniRx - Reactive Extensions for Unity
UniRx - Reactive Extensions for UnityYoshifumi Kawai
 

En vedette (11)

ゲーム開発とMVC
ゲーム開発とMVCゲーム開発とMVC
ゲーム開発とMVC
 
ゲーム開発とデザインパターン
ゲーム開発とデザインパターンゲーム開発とデザインパターン
ゲーム開発とデザインパターン
 
Sappo ro#6資料2 ー完全版ー
Sappo ro#6資料2 ー完全版ーSappo ro#6資料2 ー完全版ー
Sappo ro#6資料2 ー完全版ー
 
UniRxでPUNを使いやすくする
UniRxでPUNを使いやすくするUniRxでPUNを使いやすくする
UniRxでPUNを使いやすくする
 
ペッパソン東の陣 Microsoft 提供 API のご紹介
ペッパソン東の陣 Microsoft 提供 API のご紹介ペッパソン東の陣 Microsoft 提供 API のご紹介
ペッパソン東の陣 Microsoft 提供 API のご紹介
 
4 Colors Othello’s Algorithm @仙台 IT 文化祭 2017
4 Colors Othello’s Algorithm @仙台 IT 文化祭 20174 Colors Othello’s Algorithm @仙台 IT 文化祭 2017
4 Colors Othello’s Algorithm @仙台 IT 文化祭 2017
 
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践
 
The History of Reactive Extensions
The History of Reactive ExtensionsThe History of Reactive Extensions
The History of Reactive Extensions
 
Unity dojo amplifyshadereditor101_jpn-jp
Unity dojo amplifyshadereditor101_jpn-jpUnity dojo amplifyshadereditor101_jpn-jp
Unity dojo amplifyshadereditor101_jpn-jp
 
Unity道場aseスペシャル補足資料
Unity道場aseスペシャル補足資料Unity道場aseスペシャル補足資料
Unity道場aseスペシャル補足資料
 
UniRx - Reactive Extensions for Unity
UniRx - Reactive Extensions for UnityUniRx - Reactive Extensions for Unity
UniRx - Reactive Extensions for Unity
 

Similaire à Reactive extensions入門v0.1

PostgreSQL 12 Beta 1 New Features with Examples (Japanese)
PostgreSQL 12 Beta 1 New Features  with Examples (Japanese)PostgreSQL 12 Beta 1 New Features  with Examples (Japanese)
PostgreSQL 12 Beta 1 New Features with Examples (Japanese)Noriyoshi Shinoda
 
Linux+PHPを学んで日程調整アプリを作ろう①
Linux+PHPを学んで日程調整アプリを作ろう①Linux+PHPを学んで日程調整アプリを作ろう①
Linux+PHPを学んで日程調整アプリを作ろう①Aina Hara
 
Rの拡張を書く (R 2.15.2)
Rの拡張を書く (R 2.15.2)Rの拡張を書く (R 2.15.2)
Rの拡張を書く (R 2.15.2)itoyan110
 
Unspsc product classification process and samples
Unspsc product classification process and samples Unspsc product classification process and samples
Unspsc product classification process and samples Indra kumar
 
Citrix XenServer ® 5.6 Service Pack 2 管理者ガイド
Citrix XenServer ® 5.6 Service Pack 2 管理者ガイド Citrix XenServer ® 5.6 Service Pack 2 管理者ガイド
Citrix XenServer ® 5.6 Service Pack 2 管理者ガイド sjeho
 
技術書典4 く-35「錬金術MeetUp」 Alchemist Vol.1 サンプル版
 技術書典4  く-35「錬金術MeetUp」 Alchemist Vol.1 サンプル版 技術書典4  く-35「錬金術MeetUp」 Alchemist Vol.1 サンプル版
技術書典4 く-35「錬金術MeetUp」 Alchemist Vol.1 サンプル版Hiroyuki Ohnaka
 
ワンストップ技術書を書こう おためし版
ワンストップ技術書を書こう おためし版ワンストップ技術書を書こう おためし版
ワンストップ技術書を書こう おためし版親方 親方
 
2..nakamura thesis(2)
2..nakamura thesis(2)2..nakamura thesis(2)
2..nakamura thesis(2)Ravi Teja
 
PostgreSQL 10 Beta1 New Features (Japanese)
PostgreSQL 10 Beta1 New Features (Japanese)PostgreSQL 10 Beta1 New Features (Japanese)
PostgreSQL 10 Beta1 New Features (Japanese)Noriyoshi Shinoda
 
卒業論文「主張と根拠のクラスタを用いた 多様な主張を提示するニュース推薦手法の提案」
卒業論文「主張と根拠のクラスタを用いた 多様な主張を提示するニュース推薦手法の提案」卒業論文「主張と根拠のクラスタを用いた 多様な主張を提示するニュース推薦手法の提案」
卒業論文「主張と根拠のクラスタを用いた 多様な主張を提示するニュース推薦手法の提案」Nagi Kataoka
 
B 64014 ja-04
B 64014 ja-04B 64014 ja-04
B 64014 ja-04mt7038
 
OpenStack環境構築手順書 Havana版 バージョン2.2
OpenStack環境構築手順書 Havana版 バージョン2.2OpenStack環境構築手順書 Havana版 バージョン2.2
OpenStack環境構築手順書 Havana版 バージョン2.2VirtualTech Japan Inc.
 
完全掌握2级日本语能力考试语法对策
完全掌握2级日本语能力考试语法对策完全掌握2级日本语能力考试语法对策
完全掌握2级日本语能力考试语法对策lionlion10
 
コーディング規約「Scratch編」v1.0
コーディング規約「Scratch編」v1.0コーディング規約「Scratch編」v1.0
コーディング規約「Scratch編」v1.0satoshi59
 

Similaire à Reactive extensions入門v0.1 (20)

Tour
TourTour
Tour
 
Tour
TourTour
Tour
 
PostgreSQL 12 Beta 1 New Features with Examples (Japanese)
PostgreSQL 12 Beta 1 New Features  with Examples (Japanese)PostgreSQL 12 Beta 1 New Features  with Examples (Japanese)
PostgreSQL 12 Beta 1 New Features with Examples (Japanese)
 
Manual audio
Manual audioManual audio
Manual audio
 
Linux+PHPを学んで日程調整アプリを作ろう①
Linux+PHPを学んで日程調整アプリを作ろう①Linux+PHPを学んで日程調整アプリを作ろう①
Linux+PHPを学んで日程調整アプリを作ろう①
 
Rの拡張を書く (R 2.15.2)
Rの拡張を書く (R 2.15.2)Rの拡張を書く (R 2.15.2)
Rの拡張を書く (R 2.15.2)
 
Unspsc product classification process and samples
Unspsc product classification process and samples Unspsc product classification process and samples
Unspsc product classification process and samples
 
Citrix XenServer ® 5.6 Service Pack 2 管理者ガイド
Citrix XenServer ® 5.6 Service Pack 2 管理者ガイド Citrix XenServer ® 5.6 Service Pack 2 管理者ガイド
Citrix XenServer ® 5.6 Service Pack 2 管理者ガイド
 
技術書典4 く-35「錬金術MeetUp」 Alchemist Vol.1 サンプル版
 技術書典4  く-35「錬金術MeetUp」 Alchemist Vol.1 サンプル版 技術書典4  く-35「錬金術MeetUp」 Alchemist Vol.1 サンプル版
技術書典4 く-35「錬金術MeetUp」 Alchemist Vol.1 サンプル版
 
ワンストップ技術書を書こう おためし版
ワンストップ技術書を書こう おためし版ワンストップ技術書を書こう おためし版
ワンストップ技術書を書こう おためし版
 
2..nakamura thesis(2)
2..nakamura thesis(2)2..nakamura thesis(2)
2..nakamura thesis(2)
 
PostgreSQL 10 Beta1 New Features (Japanese)
PostgreSQL 10 Beta1 New Features (Japanese)PostgreSQL 10 Beta1 New Features (Japanese)
PostgreSQL 10 Beta1 New Features (Japanese)
 
卒業論文「主張と根拠のクラスタを用いた 多様な主張を提示するニュース推薦手法の提案」
卒業論文「主張と根拠のクラスタを用いた 多様な主張を提示するニュース推薦手法の提案」卒業論文「主張と根拠のクラスタを用いた 多様な主張を提示するニュース推薦手法の提案」
卒業論文「主張と根拠のクラスタを用いた 多様な主張を提示するニュース推薦手法の提案」
 
B 64014 ja-04
B 64014 ja-04B 64014 ja-04
B 64014 ja-04
 
Hi1
Hi1Hi1
Hi1
 
要求水準書
要求水準書要求水準書
要求水準書
 
RODEM-G 取扱説明書 v1.2 r2
RODEM-G 取扱説明書 v1.2 r2RODEM-G 取扱説明書 v1.2 r2
RODEM-G 取扱説明書 v1.2 r2
 
OpenStack環境構築手順書 Havana版 バージョン2.2
OpenStack環境構築手順書 Havana版 バージョン2.2OpenStack環境構築手順書 Havana版 バージョン2.2
OpenStack環境構築手順書 Havana版 バージョン2.2
 
完全掌握2级日本语能力考试语法对策
完全掌握2级日本语能力考试语法对策完全掌握2级日本语能力考试语法对策
完全掌握2级日本语能力考试语法对策
 
コーディング規約「Scratch編」v1.0
コーディング規約「Scratch編」v1.0コーディング規約「Scratch編」v1.0
コーディング規約「Scratch編」v1.0
 

Plus de 一希 大田

.NET 7 での ASP.NET Core Blazor の新機能ピックアップ
.NET 7 での ASP.NET Core Blazor の新機能ピックアップ.NET 7 での ASP.NET Core Blazor の新機能ピックアップ
.NET 7 での ASP.NET Core Blazor の新機能ピックアップ一希 大田
 
Azure Static Web Apps を試してみた!
Azure Static Web Apps を試してみた!Azure Static Web Apps を試してみた!
Azure Static Web Apps を試してみた!一希 大田
 
Visual studio 2019 updates pickup!
Visual studio 2019 updates pickup!Visual studio 2019 updates pickup!
Visual studio 2019 updates pickup!一希 大田
 
.NET 5 and Windows app dev
.NET 5 and Windows app dev.NET 5 and Windows app dev
.NET 5 and Windows app dev一希 大田
 
Uno Platform 触ってみた
Uno Platform 触ってみたUno Platform 触ってみた
Uno Platform 触ってみた一希 大田
 
WPF on .NET Core 3.1 で Windows 10 アプリ開発
WPF on .NET Core 3.1 で Windows 10 アプリ開発WPF on .NET Core 3.1 で Windows 10 アプリ開発
WPF on .NET Core 3.1 で Windows 10 アプリ開発一希 大田
 
.NET Core 3.0 + Windows 10 で WPF 開発
.NET Core 3.0 + Windows 10 で WPF 開発.NET Core 3.0 + Windows 10 で WPF 開発
.NET Core 3.0 + Windows 10 で WPF 開発一希 大田
 
はじめよう Azure Functions
はじめよう Azure Functionsはじめよう Azure Functions
はじめよう Azure Functions一希 大田
 
Windows 10 対応のデスクトップアプリを作る技術(事前公開版v2)
Windows 10 対応のデスクトップアプリを作る技術(事前公開版v2)Windows 10 対応のデスクトップアプリを作る技術(事前公開版v2)
Windows 10 対応のデスクトップアプリを作る技術(事前公開版v2)一希 大田
 
Xamarin.Forms アプリケーション 設計パターン
Xamarin.Forms アプリケーション 設計パターンXamarin.Forms アプリケーション 設計パターン
Xamarin.Forms アプリケーション 設計パターン一希 大田
 
Windows 10 対応のデスクトップアプリを 作る技術(事前公開版)
Windows 10 対応のデスクトップアプリを 作る技術(事前公開版)Windows 10 対応のデスクトップアプリを 作る技術(事前公開版)
Windows 10 対応のデスクトップアプリを 作る技術(事前公開版)一希 大田
 
WPF on .NET Core 3.0
WPF on .NET Core 3.0WPF on .NET Core 3.0
WPF on .NET Core 3.0一希 大田
 
Visual Studio 2019 の個人的なお勧め機能(発表時点)
Visual Studio 2019 の個人的なお勧め機能(発表時点)Visual Studio 2019 の個人的なお勧め機能(発表時点)
Visual Studio 2019 の個人的なお勧め機能(発表時点)一希 大田
 
Visual Studio 2019 の個人的なお勧め機能
Visual Studio 2019 の個人的なお勧め機能Visual Studio 2019 の個人的なお勧め機能
Visual Studio 2019 の個人的なお勧め機能一希 大田
 
Windows 10 に対応した デスクトップ アプリを作る技術(事前公開版 v2)
Windows 10 に対応した デスクトップ アプリを作る技術(事前公開版 v2)Windows 10 に対応した デスクトップ アプリを作る技術(事前公開版 v2)
Windows 10 に対応した デスクトップ アプリを作る技術(事前公開版 v2)一希 大田
 
事前公開版 Windows 10 に対応したデスクトップ アプリを作る技術 v1
事前公開版 Windows 10 に対応したデスクトップ アプリを作る技術 v1事前公開版 Windows 10 に対応したデスクトップ アプリを作る技術 v1
事前公開版 Windows 10 に対応したデスクトップ アプリを作る技術 v1一希 大田
 
スマートスピーカーのバックエンドで Azure を使う方法
スマートスピーカーのバックエンドでAzure を使う方法スマートスピーカーのバックエンドでAzure を使う方法
スマートスピーカーのバックエンドで Azure を使う方法一希 大田
 
Visual Studio App center 概要
Visual Studio App center 概要Visual Studio App center 概要
Visual Studio App center 概要一希 大田
 
はじめての HoloLens セッションの集大成お見せします!
はじめての HoloLens セッションの集大成お見せします!はじめての HoloLens セッションの集大成お見せします!
はじめての HoloLens セッションの集大成お見せします!一希 大田
 

Plus de 一希 大田 (20)

.NET 7 での ASP.NET Core Blazor の新機能ピックアップ
.NET 7 での ASP.NET Core Blazor の新機能ピックアップ.NET 7 での ASP.NET Core Blazor の新機能ピックアップ
.NET 7 での ASP.NET Core Blazor の新機能ピックアップ
 
Power Apps + C#
Power Apps + C#Power Apps + C#
Power Apps + C#
 
Azure Static Web Apps を試してみた!
Azure Static Web Apps を試してみた!Azure Static Web Apps を試してみた!
Azure Static Web Apps を試してみた!
 
Visual studio 2019 updates pickup!
Visual studio 2019 updates pickup!Visual studio 2019 updates pickup!
Visual studio 2019 updates pickup!
 
.NET 5 and Windows app dev
.NET 5 and Windows app dev.NET 5 and Windows app dev
.NET 5 and Windows app dev
 
Uno Platform 触ってみた
Uno Platform 触ってみたUno Platform 触ってみた
Uno Platform 触ってみた
 
WPF on .NET Core 3.1 で Windows 10 アプリ開発
WPF on .NET Core 3.1 で Windows 10 アプリ開発WPF on .NET Core 3.1 で Windows 10 アプリ開発
WPF on .NET Core 3.1 で Windows 10 アプリ開発
 
.NET Core 3.0 + Windows 10 で WPF 開発
.NET Core 3.0 + Windows 10 で WPF 開発.NET Core 3.0 + Windows 10 で WPF 開発
.NET Core 3.0 + Windows 10 で WPF 開発
 
はじめよう Azure Functions
はじめよう Azure Functionsはじめよう Azure Functions
はじめよう Azure Functions
 
Windows 10 対応のデスクトップアプリを作る技術(事前公開版v2)
Windows 10 対応のデスクトップアプリを作る技術(事前公開版v2)Windows 10 対応のデスクトップアプリを作る技術(事前公開版v2)
Windows 10 対応のデスクトップアプリを作る技術(事前公開版v2)
 
Xamarin.Forms アプリケーション 設計パターン
Xamarin.Forms アプリケーション 設計パターンXamarin.Forms アプリケーション 設計パターン
Xamarin.Forms アプリケーション 設計パターン
 
Windows 10 対応のデスクトップアプリを 作る技術(事前公開版)
Windows 10 対応のデスクトップアプリを 作る技術(事前公開版)Windows 10 対応のデスクトップアプリを 作る技術(事前公開版)
Windows 10 対応のデスクトップアプリを 作る技術(事前公開版)
 
WPF on .NET Core 3.0
WPF on .NET Core 3.0WPF on .NET Core 3.0
WPF on .NET Core 3.0
 
Visual Studio 2019 の個人的なお勧め機能(発表時点)
Visual Studio 2019 の個人的なお勧め機能(発表時点)Visual Studio 2019 の個人的なお勧め機能(発表時点)
Visual Studio 2019 の個人的なお勧め機能(発表時点)
 
Visual Studio 2019 の個人的なお勧め機能
Visual Studio 2019 の個人的なお勧め機能Visual Studio 2019 の個人的なお勧め機能
Visual Studio 2019 の個人的なお勧め機能
 
Windows 10 に対応した デスクトップ アプリを作る技術(事前公開版 v2)
Windows 10 に対応した デスクトップ アプリを作る技術(事前公開版 v2)Windows 10 に対応した デスクトップ アプリを作る技術(事前公開版 v2)
Windows 10 に対応した デスクトップ アプリを作る技術(事前公開版 v2)
 
事前公開版 Windows 10 に対応したデスクトップ アプリを作る技術 v1
事前公開版 Windows 10 に対応したデスクトップ アプリを作る技術 v1事前公開版 Windows 10 に対応したデスクトップ アプリを作る技術 v1
事前公開版 Windows 10 に対応したデスクトップ アプリを作る技術 v1
 
スマートスピーカーのバックエンドで Azure を使う方法
スマートスピーカーのバックエンドでAzure を使う方法スマートスピーカーのバックエンドでAzure を使う方法
スマートスピーカーのバックエンドで Azure を使う方法
 
Visual Studio App center 概要
Visual Studio App center 概要Visual Studio App center 概要
Visual Studio App center 概要
 
はじめての HoloLens セッションの集大成お見せします!
はじめての HoloLens セッションの集大成お見せします!はじめての HoloLens セッションの集大成お見せします!
はじめての HoloLens セッションの集大成お見せします!
 

Reactive extensions入門v0.1

  • 1. Reactive Extensions 入門 2012/03/05 0.1 版 okazuk
  • 2. 改版履歴 版数 内容 日付 0.1 基本メソッドの説明を書いた初版作成 2012/03/05 ii
  • 3. 内容 1. はじめに.............................................................................................................................................................. 1 1.1. 前提環境 ............................................................................................................................................................ 1 1.2. 対象読者 ............................................................................................................................................................ 1 1.3. 謝辞 ................................................................................................................................................................... 1 2. REACTIVE EXTENSIONS とは ........................................................................................................................ 2 2.1. OBSERVER パターン .......................................................................................................................................... 2 2.2. REACTIVE EXTENSIONS で提供されている機能 ................................................................................................ 2 2.3. IOBSERVALBE<T>゗ンターフェースと IOBSERVER<T>゗ンターフェース ..................................................... 3 2.4. REACTIVE EXTENSIONS の機能を使った書き直し ............................................................................................ 8 3. IOBSERVABLE<T>のファクトリメソッド ...................................................................................................... 11 3.1. 基本的なフゔクトリメソッドの使用 ............................................................................................................... 11 3.2. 指定された値を返す IOBSERVABLE<T>を返すフゔクトリメソッド .............................................................. 12 3.2.1. Observable.Return メソッド ................................................................................................................. 12 3.2.2. Observable.Repeat メソッド.................................................................................................................. 12 3.2.3. Observable.Range メソッド ................................................................................................................... 13 3.2.4. Observable.Generate メソッド .............................................................................................................. 14 3.2.5. Observable.Defer メソッド .................................................................................................................... 15 3.2.6. Observable.Create メソッド .................................................................................................................. 17 3.2.7. Observable.Throw メソッド .................................................................................................................. 18 3.3. ここまでに紹介した IOBSERVABLE<T>の動作 ............................................................................................... 19 3.4. リソースの確保を伴う IOBSERVABLE<T> ...................................................................................................... 19 3.4.1. Observable.Uting メソッド .................................................................................................................... 20 3.5. 時間と共に値を発行する IOBSERVABLE<T> .................................................................................................. 21 3.5.1. Observable.Timer メソッド ................................................................................................................... 21 3.5.2. Observable.Interval メソッド ................................................................................................................ 23 3.5.3. Observable.Generate メソッド .............................................................................................................. 24 3.6. COLD な IOBSERVABLE<T>と HOT な IOBSERVABLE<T> .............................................................................. 25 3.6.1. Observable.FromEvent メソッド .......................................................................................................... 28 i
  • 4. 3.6.2. Observable.Start メソッド..................................................................................................................... 30 3.6.3. Observable.ToAsync メソッド ............................................................................................................... 32 3.6.4. Observable.FromAsyncPattern メソッド ............................................................................................. 33 4. IOBSERVABLE の拡張メソッド ...................................................................................................................... 35 4.1. LINQ のメソッド ............................................................................................................................................ 35 4.2. 単一の値を取得するメソッド ......................................................................................................................... 38 4.2.1. First メソッドと Last メソッド ............................................................................................................. 38 4.2.2. FirstOrDefault メソッドと LastOrDefault メソッド ........................................................................... 41 4.2.3. ElementAt メソッド ............................................................................................................................... 42 4.2.4. ElementAtOrDefault メソッド .............................................................................................................. 45 4.2.5. Single メソッド ....................................................................................................................................... 46 4.2.6. SingleOrDefault メソッド...................................................................................................................... 50 4.3. 値と飛ばす、値を拾うメソッド ...................................................................................................................... 52 4.3.1. Skip と Take メソッド ............................................................................................................................ 52 4.3.2. Repeat メソッドとの組み合わせ ............................................................................................................ 53 4.3.3. SkipWhile と TakeWhile メソッド ........................................................................................................ 54 4.3.4. SkipUntil と TakeUntil メソッド .......................................................................................................... 55 4.3.5. SkipUntil と TakeUntil を使ったドラッグの処理 ................................................................................. 56 4.3.6. SkipLast と TakeLast メソッド ............................................................................................................. 61 4.4. DO メソッド .................................................................................................................................................... 62 4.4.1. Do メソッド使用時の注意点 ................................................................................................................... 64 4.5. エラー処理関連のメソッド ............................................................................................................................. 64 4.5.1. Catch メソッド ....................................................................................................................................... 64 4.5.2. Finally メソッド ..................................................................................................................................... 67 4.5.3. OnErrorResumeNext メソッド ............................................................................................................. 70 4.5.4. Retry メソッド ........................................................................................................................................ 72 4.6. IOBSERVABLE<T>の値を収集するメソッド ................................................................................................... 75 4.6.1. ToArray メソッド ................................................................................................................................... 75 4.6.2. ToDictionary メソッド ........................................................................................................................... 76 4.6.3. ToList メソッド ...................................................................................................................................... 77 4.6.4. ToLookup メソッド ................................................................................................................................ 78 ii
  • 5. 4.6.5. Max メソッドと Min メソッドと Average メソッド ............................................................................. 79 4.6.6. MaxBy メソッドと MinBy メソッド ...................................................................................................... 82 4.6.7. Count メソッドと LongCount メソッド ................................................................................................ 83 4.6.8. Any メソッド .......................................................................................................................................... 84 4.6.9. All メソッド ............................................................................................................................................ 85 4.6.10. Aggregate メソッド ................................................................................................................................ 86 4.6.11. Scan メソッド ......................................................................................................................................... 91 4.6.12. GroupBy メソッド .................................................................................................................................. 93 4.6.13. GroupByUntil メソッド ......................................................................................................................... 95 4.7. IOBSERVABLE<T>から IENUMERABLE<T>への変換メソッド ....................................................................... 99 4.7.1. ToEnumerable メソッド ........................................................................................................................ 99 4.7.2. Latest メソッド .................................................................................................................................... 101 4.7.3. MostRecent メソッド ........................................................................................................................... 104 4.7.4. Next メソッド ....................................................................................................................................... 106 4.8. TOEVENT メソッド........................................................................................................................................ 108 4.9. 重複を排除するメソッド ............................................................................................................................... 109 4.9.1. Distinct メソッド .................................................................................................................................. 109 4.9.2. Distinct メソッドのオーバーロード ..................................................................................................... 110 4.9.3. DistinctUntilChanged メソッド .......................................................................................................... 113 4.10. BUFFER メソッドと WINDOW メソッド ........................................................................................................ 114 4.10.1. 数でまとめる Buffer メソッドのオーバーロード ................................................................................. 114 4.10.2. 時間でまとめる Buffer メソッドのオーバーロード ............................................................................. 118 4.10.3. 任意のタイミングで値をまとめる Buffer メソッドのオーバーロード ................................................ 121 4.10.4. 時間と数でまとめる Buffer メソッドのオーバーロード ...................................................................... 125 4.10.5. Window メソッド.................................................................................................................................. 127 4.11. 発行された値にたいして時間でフゖルタ・操作するメソッド ..................................................................... 130 4.11.1. Sample メソッド ................................................................................................................................... 130 4.11.2. Throttle メソッド ................................................................................................................................. 133 4.11.3. Delay メソッド ..................................................................................................................................... 135 4.11.4. Timeout メソッド ................................................................................................................................. 136 4.12. 時間に関する情報を付与する拡張メソッド .................................................................................................. 138 iii
  • 6. 4.12.1. Timestamp メソッド ............................................................................................................................ 139 4.12.2. TimeInterval メソッド ......................................................................................................................... 140 4.13. 型変換を行う拡張メソッド ........................................................................................................................... 141 4.13.1. Cast メソッド ....................................................................................................................................... 141 4.13.2. OfType メソッド ................................................................................................................................... 142 4.14. COLD から HOT へ変換する拡張メソッド ..................................................................................................... 143 4.14.1. Publish メソッド .................................................................................................................................. 143 4.14.2. RefCount メソッド ............................................................................................................................... 148 4.14.3. 引数を受け取る Publish メソッドのオーバーロード ........................................................................... 151 4.14.4. PublishLast メソッド ........................................................................................................................... 152 4.14.5. Replay メソッド.................................................................................................................................... 153 4.14.6. Multicast メソッド ............................................................................................................................... 155 5. SUBJECT 系クラス ........................................................................................................................................ 159 5.1. SUBJECT<T>クラス ...................................................................................................................................... 159 5.2. BEHAVIORSUBJECT<T>クラス...................................................................................................................... 161 5.3. ASYNCSUBJECT<T>クラス ........................................................................................................................... 162 5.4. REPLAYSUBJECT<T>クラス .......................................................................................................................... 164 6. IOBSERVABLE の合成 .................................................................................................................................. 165 6.1. MERGE メソッド ........................................................................................................................................... 165 6.2. SELECTMANY メソッド ................................................................................................................................. 169 6.3. SWITCH メソッド........................................................................................................................................... 172 6.4. CONCAT メソッド .......................................................................................................................................... 176 6.5. ZIP メソッド .................................................................................................................................................. 178 6.6. AMB メソッド ................................................................................................................................................ 179 6.7. COMBINELATEST メソッド ............................................................................................................................ 180 6.8. STARTWITH メソッド .................................................................................................................................... 182 6.9. JOIN メソッド ............................................................................................................................................... 183 6.10. GROUPJOIN メソッド .................................................................................................................................... 186 6.11. WHEN メソッド ............................................................................................................................................. 189 6.11.1. Plan<TResult>クラスの作成 ............................................................................................................... 189 iv
  • 7. 6.11.2. When メソッドの使用例 ....................................................................................................................... 190 6.11.3. まとめ .................................................................................................................................................... 193 7. SCHEDULER ................................................................................................................................................ 193 7.1. 実行場所の切り替え ...................................................................................................................................... 194 7.2. IOBSERVABLE<T>生成時の SCHEDULER の指定方法 ................................................................................... 195 7.2.1. デフォルトの Scheduler ....................................................................................................................... 197 7.3. SCHEDULER の切り替え ................................................................................................................................ 197 7.3.1. ObserveOn メソッド ............................................................................................................................ 197 7.3.2. ObserveOn の使用用途 ......................................................................................................................... 198 7.4. 時間を制御する SCHEDULER ......................................................................................................................... 199 7.4.1. HistoricalScheduler クラス ................................................................................................................. 199 8. 応用編 ............................................................................................................................................................. 200 8.1. センサー監視 ................................................................................................................................................. 200 9. 参考サイト ...................................................................................................................................................... 203 v
  • 8. 1. はじめに ここでは、Reactive Extensions(下記リンク)の著者自身の理解を深めるために著者自身の Reactive Extensions の理解している内容を記載します。 Dev Lab Reactive Extensions ホームページ 1.1. 前提環境 ここでは、下記の環境を前提に説明を行います。  Visual Studio 2010 SP1 Ultimate  .NET Framework 4  Reactive Extensions 1.0.* Visual Studio は、Visual C# 2010 SP1 Express Edition でも動作可能です。 1.2. 対象読者 Reactive Extensions によるプログラミングに興味がある方。 1.3. 謝辞 本ドキュメントのもとになった著者の Blog エントリの記事に対してコメント等で指摘していただ いた方々に感謝いたします。特に@neuecc さんには、サ゗トの情報や私の理解不足による誤った 記載など丁寧に対応していただきとても感謝しています。 1
  • 9. 2. Reactive Extensions とは Reactive Extensions は、公式ページに下記のように説明があります。 The Reactive Extensions (Rx)... ...is a library to compose asynchronous and event-based programs using observable collections and LINQ-style query operators. 私の拙い英語力で和訳を行うと「Reactive Extensions は、監視可能なコレクションと LINQ スタ ゗ルのオペレーションを使用して非同期と゗ベントベースのプログラムを合成するラ゗ブラリで す。」となります。 個人的な解釈としては、Reactive Extensions とは何かしらの値を 0 回以上通知するもの(C#の event や非同期処理やタ゗マーなど etc…)を統一的なプログラミングモデルで扱えるようにした ものです。 そして、この統一的なプログラミングモデルを提供するための要となる゗ンターフェー スが System 名前空間の下にある IObservable<T>と IObserver<T>です。 2.1. Observer パターン Observer と Observable という名前からもわかる通り、この゗ンターフェースはデザ゗ンパター ンの Observer パターンのための機構を提供します。IObserver<T>゗ンターフェースが、 IObservable<T>゗ンターフェースの発行する゗ベントを監視するという構造になります。 IObserver<T>゗ンターフェースには下記の 3 つのメソッドが定義されています。 1. void OnNext(T value)メソッド IObservable<T>から発生した通知を受け取って処理を行います 2. void OnError(Exception ex)メソッド IObservable<T>で発生した例外を受け取って処理を行います。 3. void OnCompleted()メソッド IObservable<T>からの通知が終了した時の処理を行います。 対になる IObservable<T>には下記の 1 つのメソッドが定義されています。 1. IDisposable Subscribe(IObserver<T> observer)メソッド 引数で受け取った Observer に゗ベントの通知を行うようにします。戻り値の IDisposable の Dispose メソッドを呼び出すと通知を取り消します。 Reactive Extensions は、この Observer パターンを土台にして構築されたラ゗ブラリになります。 2.2. Reactive Extensions で提供されている機能 Reactive Extensions は、この IObservable<T>と IObserver<T>をベースに下記のような機能 を提供しています。 1. IObservable<T>のフゔクトリメソッド Reactive Extensions には IObservable<T>を返すフゔクトリメソッドが多数用意されてい ます。 .NET の標準の゗ベントから IObservable<T>を生成するメソッドや、 非同期呼び出し、 2
  • 10. タ゗マー、シーケンス、特定のルールで生成される値の集合 etc…さまざまなものが提供され ています。 2. IObservable<T>の拡張メソッド IObservable<T>と IObserver<T>だけでは゗ベントの発行と購読の関係にしかなりません。 Reactive Extensions では、ここに LINQ スタ゗ルの拡張メソッドを提供することで IObservable<T>から発行された値をフゖルタリングしたり、 発行された値を元に別の処理を 行ったり、発行された値の変換を行ったりすることが出来ます。 IObserver<T>生成へのショートカット IObserver<T>を実装しなくても、ラムダ式から IObserver<T>を内部的に生成してくれるため 実際に Reactive Extensions を使用するときには IObserver<T>゗ンターフェースを実装するケ ースは、ほとんどありません。 3. 柔軟なスレッドの切り替え機能 IObservable<T>から発行された値に対する処理を何処のスレッドで実行するのか柔軟に切 り替える機能が提供されています。このためバックグラウンドで時間のかかる処理を行い、UI スレッドに切り替えて画面の更新を行うといった処理が簡単に行えるようになります。 以上が、Reactive Extensions で提供されている機能の全体像になります。次からは、Reactive Extensions の基本となる IObservable<T>゗ンターフェースと IObserver<T>゗ンターフェー スを見ていこうと思います。 2.3. IObservalbe<T>インターフェースと IObserver<T>インターフェース ここでは、Reactive Extensions の機能の要となる IObservable<T>と IObserver<T>を実装し て、その動作を確認します。まずは、Observer パターンでの監視役となる IObserver<T>から実 装を行います。IObserver<T>゗ンターフェースは、先に示したように OnNext と OnError と OnCompleted の3つのメソッドからなります。この3種類のメソッド内に IObservable<T>か ら通知された値を受け取った時の処理を行います。ここでは、IObservable<T>から通知された 値を単純にコンソールに出力するものを作成します。 namespace IObservableIObserverImpl { using System; // 監視する人 class PrintObserver : IObserver<int> { // 監視対象から通知が来たときの処理 public void OnNext(int value) { Console.WriteLine("OnNext({0}) called.", value); } 3
  • 11. // 完了通知が来たときの処理 public void OnCompleted() { Console.WriteLine("OnCompleted called."); } // エラー通知が来たときの処理 public void OnError(Exception error) { Console.WriteLine("OnError({0}) called.", error.Message); } } } 単純に、OnNext と OnCompleted と OnError で標準出力に値を出力しています。次に IObservable<T>を実装したコードを示します。 namespace IObservableIObserverImpl { using System; using System.Collections.Generic; /// <summary> /// 監視されるクラス /// </summary> class NumberObservable : IObservable<int> { // 自分を監視してる人を管理するリスト private List<IObserver<int>> observers = new List<IObserver<int>>(); // 自分を監視してる人に通知を行う // 0 を渡したらエラー通知 public void Execute(int value) { if (value == 0) { foreach (var obs in observers) { obs.OnError(new Exception("value is 0")); 4
  • 12. } // エラーが起きたので処理は終了 this.observers.Clear(); return; } foreach (var obs in observers) { obs.OnNext(value); } } // 完了通知 public void Completed() { foreach (var obs in observers) { obs.OnCompleted(); } // 完了したので監視してる人たちをクリゕ this.observers.Clear(); } // 監視してる人を追加する。 // 戻り値の IDisposable を Dispose すると監視から外れる。 public IDisposable Subscribe(IObserver<int> observer) { this.observers.Add(observer); return new RemoveListDisposable(observers, observer); } // Dispose が呼ばれたら observer を監視対象から削除する private class RemoveListDisposable : IDisposable { private List<IObserver<int>> observers = new List<IObserver<int>>(); private IObserver<int> observer; 5
  • 13. public RemoveListDisposable(List<IObserver<int>> observers, IObserver<int> observer) { this.observers = observers; this.observer = observer; } public void Dispose() { if (this.observers == null) { return; } if (observers.IndexOf(observer) != -1) { this.observers.Remove(observer); } this.observers = null; this.observer = null; } } } } IObservable<T>の実装は IObserver<T>に比べて複雑になっています。これは、 IObservable<T>゗ンターフェースが IObserver<T>を自分自身の監視役として登録する Subscribe メソッドしか提供していないため、その他の監視役の IObserver<T>の保持や、 Subscribe メソッドの戻り値の IDosposable の Dispose を呼び出したときの監視役解除の処理を 作りこんでいるためです。どちらも一般的な C#によるプログラミングの範囲の内容になるので詳 細は割愛します。 最期に、この PrintObserver クラスと NumberObservable クラスを使ったサン プルプログラムを以下に示します。 namespace IObservableIObserverImpl { using System; class Program 6
  • 14. { static void Main(string[] args) { // 監視される人を作成 var source = new NumberObservable(); // 監視役を2つ登録 var sbscriber1 = source.Subscribe(new PrintObserver()); var sbscriber2 = source.Subscribe(new PrintObserver()); // 監視される人の処理を実行 Console.WriteLine("## Execute(1)"); source.Execute(1); // 片方を監視する人から解雇 Console.WriteLine("## Dispose"); sbscriber2.Dispose(); // 再度処理を実行 Console.WriteLine("## Execute(2)"); source.Execute(2); // エラーを起こしてみる Console.WriteLine("## Execute(0)"); source.Execute(0); // 完了通知 // もう 1 つ監視役を追加して完了通知を行う var sbscriber3 = source.Subscribe(new PrintObserver()); Console.WriteLine("## Completed"); source.Completed(); } } } 上記のプログラムは、NumberObservable 型の変数 source に PrintObserver を 2 つ登録してい ます。その状態で Execute メソッドを呼んだり Dispose を読んだりエラーを起こしたりして出力 を確認しています。このプログラムを動かすと下記のような結果になります。 ## Execute(1) OnNext(1) called. OnNext(1) called. ## Dispose 7
  • 15. ## Execute(2) OnNext(2) called. ## Execute(0) OnError(value is 0) called. ## Completed OnCompleted called. 最初の Execute では、PrintObserver を 2 つ登録しているので 2 回 OnNext が呼ばれていること が確認出来ます。 次に片方を Dispose した後では Execute を読んでも 1 回しか OnNext が呼ばれ ません。 Execute メソッドの引数に 0 を渡してエラーを起こした場合と処理を完了させたときも、 PrintObserver に処理が伝わっていることが確認できます。 2.4. Reactive Extensions の機能を使った書き直し ここまで書いてきたプログラムは、Reactive Extensions の説明というよりは IObservable<T> ゗ンターフェースと IObserver<T>゗ンターフェースを実装して使用しただけの Observer パタ ーンの1実装例です。ここでは、このプログラムを Reactive Extensions が提供する便利な拡張 メソッドやクラスを使って書き換えを行います。 Reactive Extensions を使ったプログラムでは、頻繁に IObservable<T>゗ンターフェースの Subscribe メソッドを使用して通知に対するゕクションを設定します。この時、実行したい処理の 単位でクラスを作成するのは現実的ではありません。そのため、Reactive Extensions では System.ObservableExtensions クラスで IObservable<T>゗ンターフェースの拡張メソッドを 定義しています。主な拡張メソッドは下記の 3 つになります。どれもデリゲートを受け取るタ゗ プになります。  void Subscribe<T>(this IObservable<T> source, Action<T> onNext)  void Subscribe<T>( this IObservable<T> source, Action<T> onNext, Action onCompleted)  void Subscribe<T>( this IObservable<T> source, Action<T> onNext, Action<Exception> onError, Action onCompleted) この拡張メソッドを使うことでデリゲートで IObserver<T>゗ンターフェースの OnNext メソッ ドと OnError メソッドと OnCompleted メソッドを指定するだけで内部で IObserver<T>を継承 したクラスを作成して IObservable<T>゗ンターフェースの Subscribe(IObserver<T>)メソッ ドへ渡してくれます。このため、Reactive Extensions を使う上では IObserver<T>゗ンターフ ェースを実装することは、ほぼ無くなります。 (私は今まで実際の処理を書いていて実装したこと は有りません)上記の拡張メソッドを使うためには Reactive Extensions をプロジェクトの参照 に追加します。 Nuget で Rx-Main という名前のパッケージをプロジェクトに追加します。 (Express Edition の方は nuget コマンドラ゗ンを゗ンストールして nuget install rx-main でダウンロード されるので手動で参照に追加してください)そして、 Main のプログラムを下記のように変更します。 // 監視される人を作成 var source = new NumberObservable(); // 2 つ監視役を登録 8
  • 16. var subscriber1 = source.Subscribe( // OnNext value => Console.WriteLine("OnNext({0}) called.", value), // OnError ex => Console.WriteLine("OnError({0}) called.", ex.Message), // OnCompleted () => Console.WriteLine("OnCompleted() called.")); var subscriber2 = source.Subscribe( // OnNext value => Console.WriteLine("OnNext({0}) called.", value), // OnError ex => Console.WriteLine("OnError({0}) called.", ex.Message), // OnCompleted () => Console.WriteLine("OnCompleted() called.")); // 監視される人の処理を実行 Console.WriteLine("## Execute(1)"); source.Execute(1); // 1 つを監視する人から解雇 Console.WriteLine("## Dispose"); subscriber2.Dispose(); // 再度処理を実行 Console.WriteLine("## Execute(2)"); source.Execute(2); // エラーを起こしてみる Console.WriteLine("## Execute(0)"); source.Execute(0); // もう 1 つ監視役を追加して完了通知を行う var sbscriber3 = source.Subscribe( // OnNext value => Console.WriteLine("OnNext({0}) called.", value), // OnError ex => Console.WriteLine("OnError({0}) called.", ex.Message), // OnCompleted () => Console.WriteLine("OnCompleted() called.")); Console.WriteLine("## Completed"); source.Completed(); 9
  • 17. 引数を 3 つ受け取るタ゗プの Subscribe 拡張メソッドを使用しているため PrintObserver クラス は不要になります。今回の例では、同じ処理を何度も Subscribe しているのでメソッドとして切 り出すなりしたほうがコードの重複が無くなりますが、 サンプルとしての見通しのためにあえて 1 メソッド内に重複コードを書いています。 次に IObservable<T>の実装クラスですが、これも IObservable<T>を実装したクラスが提供さ れています。System.Reactive.Subjects.Subject<T>クラスがそれにあたります。このクラスは IObservable<T>゗ンターフェースと IObserver<T>゗ンターフェースの両方を実装していて OnNext や OnError や OnCompleted などの IObserver<T>゗ンターフェースで提供されている メソッドを呼び出すと IObservable<T>゗ンターフェースの Subscribe メソッドで監視対象とし て追加されている IObserver<T>に処理を通知します。このクラスをラップする形で使うと簡単 に IObservable<T>゗ンターフェースを実装することが出来ます。 namespace UseSubscribeMethod { using System; using System.Reactive.Subjects; class NumberObservable : IObservable<int> { // IObservable<T>と IObserver<T>の両方を兼ねるクラス private Subject<int> source = new Subject<int>(); // 自分を監視してる人に通知を行う // 0 を渡したらエラー通知 public void Execute(int value) { if (value == 0) { this.source.OnError(new Exception("value is 0")); // エラー状態じゃないまっさらな Subject を再作成 this.source = new Subject<int>(); return; } this.source.OnNext(value); } // 完了通知 public void Completed() 10
  • 18. { this.source.OnCompleted(); } // 監視してる人を追加する。 // 戻り値の IDisposable を Dispose すると監視から外れる。 public IDisposable Subscribe(IObserver<int> observer) { return this.source.Subscribe(observer); } } } これで、初期のプログラムと同じ動作を実装出来ました。ただし、Reactive Extensions を普通に 使っている範囲では、 Subject<T>クラスは使用することは少ないです。本来は、IObservable<T> を実装したクラスを生成するためのフゔクトリメソッドが用意されているので、 そちらを利用する ことのほうが多いです。 しかし、 動作確認をするためには自分で値の発行などが細かく制御できる Subject<T>クラスを、これから先のサンプルで使用するために紹介しました。 3. IObservable<T>のファクトリメソッド ここでは、Reactive Extensions で提供される IObservable<T>を作成するフゔクトリメソッド を紹介します。通常の Reactive Extensions を使ったプログラミングでは、提供されている様々 なフゔクトリメソッドから IObservable<T>を生成して使用します。そのため、どのような IObservable<T>の生成方法があるかを把握していることは Reactive Extensions を使う上でと ても重要な要素になります。フゔクトリメソッドは基本的に System.Reactive.Linq.Observable クラスの static メソッドとして提供されています。メソッドの一覧は下記の MSDN のドキュメン トを参照してください。 MSDN Observable クラス http://msdn.microsoft.com/en-us/library/system.reactive.linq.observable(v=VS.103).as px 3.1. 基本的なファクトリメソッドの使用 ここでは、数多くある Observable クラスのフゔクトリメソッドから基本的なものをいくつか紹介 します。 11
  • 19. 3.2. 指定された値を返す IObservable<T>を返すファクトリメソッド 3.2.1. Observable.Return メソッド まず、一番動作を理解しやすい指定した値を通知する IObservable<T>を作成するメソッドから 使用します。最初に紹介するメソッドは Return メソッドになります。これは引数に指定した値を 通知する IObservable<T>を作成します。コード例を以下に示します。 // 10 を発行する IObservable<int>を作成する var source = Observable.Return(10); // 購読 var subscription = source.Subscribe( i => Console.WriteLine("OnNext({0})", i), ex => Console.WriteLine("OnError({0})", ex.Message), () => Console.WriteLine("Completed()")); // 購読の停止(この場合意味はない) subscription.Dispose(); コメントにあるように、このコードは 10 という値を発行する IObservable<int>を作成していま す。実行結果は下記のようになります。 OnNext(10) Completed() Return で作成した IObservable<T>は値を 1 つ発行すると、それ以降発行する値が無いため終了 状態になります。そのため Subscribe をすると実行結果のように OnNext の後に Completed が 呼ばれます。また、ここでは示していませんが 2 回 Subscribe を行うと値の発行と終了の通知を 再び行います。上記のコード例で言うと、2 回目の Subscribe の呼び出しでも、OnNext(10)と Completed()が表示されます。 3.2.2. Observable.Repeat メソッド 次は、同じ値を指定した回数発行する IObservable<T>を返すメソッドになります。コード例を 下記に示します。 // 2 を 5 回発行する IObservable<int>を作成する var source = Observable.Repeat(2, 5); // 購読 var subscription = source.Subscribe( i => Console.WriteLine("OnNext({0})", i), ex => Console.WriteLine("OnError({0})", ex.Message), () => Console.WriteLine("Completed()")); // 購読停止(この場合意味はない) subscription.Dispose(); 12
  • 20. これを実行すると下記のようになります。 OnNext(2) OnNext(2) OnNext(2) OnNext(2) OnNext(2) Completed() 同じ値をひたすら発行しているのがわかります。 3.2.3. Observable.Range メソッド このメソッドは、指定した値から 1 ずつカウントゕップした値を指定した個数だけ返します。コ ード例を下記に示します。 // 1 から始まる値を 10 個発行する IObservable<int>を作成する var source = Observable.Range(1, 10); // 購読 var subscription = source.Subscribe( i => Console.WriteLine("OnNext({0})", i), ex => Console.WriteLine("OnError({0})", ex.Message), () => Console.WriteLine("Completed()")); // 購読停止(この場合意味はない) subscription.Dispose(); 1 からカウントゕップする値を 10 個発行するので 1~10 の値を発行する IObservable<int>を作 成しています。実行例を下記に示します。 OnNext(1) OnNext(2) OnNext(3) OnNext(4) OnNext(5) OnNext(6) OnNext(7) OnNext(8) OnNext(9) OnNext(10) Completed() 13
  • 21. 3.2.3.1. IObservable<T>の拡張メソッドの Repeat ここまでは Observable クラスに定義された IObservable<T>を返すメソッドを使ってきました が、ここで少し横道に逸れて IObservable<T>の拡張メソッドとして定義された Repeat メソッ ドを紹介したいと思います。この拡張メソッドも Observable クラスに定義されています。これま でのメソッドとの違いは純粋な static メソッドではなく、IObservable<T>の拡張メソッドとし て定義されている点です。 この Repeat 拡張メソッドは、 IObservable<T>が発行する値を指定し た回数繰り返す IObservable<T>を作成します。Range メソッドと組み合わせて使用した例を下 記に示します。 // 1 から始まる値を 3 個発行する IObservable<int>を作成する var source = Observable.Range(1, 3); // そして、それを 3 回繰り返す IObservable<int>を作成する source = source.Repeat(3); // 購読 var subscription = source.Subscribe( i => Console.WriteLine("OnNext({0})", i), ex => Console.WriteLine("OnError({0})", ex.Message), () => Console.WriteLine("Completed()")); // 購読停止(この場合意味はない) subscription.Dispose(); 実行結果は下記のようになります。1~3 の値が 3 回発行されているのがわかります。 OnNext(1) OnNext(2) OnNext(3) OnNext(1) OnNext(2) OnNext(3) OnNext(1) OnNext(2) OnNext(3) Completed() 3.2.4. Observable.Generate メソッド 次は、Generate メソッドです。このメソッドは for 文に近い使用感のメソッドになっています。 第一引数で初期値状態、第二引数で継続の条件、第三引数で更新処理、第四引数で発行する値の生 成を行う処理を渡します。 コードを見ていただくと゗メージがわきやすいと思うので下記にコード 例を示します。 // 初期値 0, 値が 10 より小さい間, 値は 1 ずつ゗ンクリメントして, 値を二乗したものを発行する 14
  • 22. // IObservable<int>を作成する。 // for (int i = 0; i < 10; i++) { yield return i * i; }のような゗メージ var source = Observable.Generate(0, i => i < 10, i => ++i, i => i * i); // 購読 var subscription = source.Subscribe( i => Console.WriteLine("OnNext({0})", i), ex => Console.WriteLine("OnError({0})", ex.Message), () => Console.WriteLine("Completed()")); // 購読停止(この場合意味はない) subscription.Dispose(); このコードを実行すると 0~9 までの値を二乗したものを発行する IObservable<int>が作成され ます。実行結果は下記のようになります。 OnNext(0) OnNext(1) OnNext(4) OnNext(9) OnNext(16) OnNext(25) OnNext(36) OnNext(49) OnNext(64) OnNext(81) Completed() 0~9 までの値を二乗した値が発行されているのが確認出来ます。 3.2.5. Observable.Defer メソッド 次に紹介するメソッドは Defer メソッドです。このメソッドは IObservable<T>を直接返すラム ダ式を引数に渡します。Subscribe メソッドが呼ばれる度に、Defer メソッドが実行されて IObservable<T>が作成されます。コード例を以下に示します。 // 1, 2, 3 と順番に値を発行して終了する IObservable<int>を生成する var source = Observable.Defer<int>(() => { Console.WriteLine("# Defar method called."); // ReplaySubject<T>は Subject<T>の亜種で Subscribe されると // 今まで行われた操作を全てリプレ゗する。 var s = new ReplaySubject<int>(); s.OnNext(1); 15
  • 23. s.OnNext(2); s.OnNext(3); s.OnCompleted(); // AsObservable で IObservable<T>へ変換できる。 return s.AsObservable(); }); // 購読(source は ReplaySubject で作っているので Defer メソッド内でした操作が再生される) var subscription1 = source.Subscribe( i => Console.WriteLine("OnNext({0})", i), ex => Console.WriteLine("OnError({0})", ex.Message), () => Console.WriteLine("Completed()")); var subscription2 = source.Subscribe( i => Console.WriteLine("OnNext({0})", i), ex => Console.WriteLine("OnError({0})", ex.Message), () => Console.WriteLine("Completed()")); // 購読停止(この場合意味はない) subscription1.Dispose(); subscription2.Dispose(); 実行結果は下記のようになります。2 回 Subscribe しているので 2 回 Defer メソッドが呼ばれて いることが確認出来ます。 # Defar method called. OnNext(1) OnNext(2) OnNext(3) Completed() # Defar method called. OnNext(1) OnNext(2) OnNext(3) Completed() Defer メソッド内で使用している ReplaySubject<T>クラスは、コメント内にあるように Subject<T>クラスの親戚のクラスです。 Subject<T>クラスが Subscribe される前の操作は通知 しないのに対して ReplaySubject<T>クラスは、Subscribe される前の操作も通知する点が異な ります。試しに Defer メソッド内の ReplaySubject<T>を普通の Subject<T>に変更して実行す ると下記のような結果になります。 # Defar method called. Completed() 16
  • 24. # Defar method called. Completed() Defer メソッドで返された IObservable<int>は既に通知する値が無く完了した状態になってい るため、OnCompleted だけが実行されます。 3.2.6. Observable.Create メソッド 次は、Create メソッドを紹介します。このメソッドは、引数の形が特殊で IObserver<T>を受け 取って Action を返すラムダ式を引数に受け取ります。引数で受け取る IObserver<T>には OnNext や OnErrror や OnCompleted などの操作を行います。ここで行った操作に応じた値が Create メソッドの戻り値の IObservable<T>で発行される値になります。 最期に戻り値の Action ですが、これは Dispose された時に実行される処理になります。Create メソッド内でリソースや ゗ベントの購読などをしていた場合に解放する処理を行うと良いと思います。 では、コード例を下 記に示します。 // 1, 2, 3 と順番に値を発行して終了する IObservable<int>を生成する var source = Observable.Create<int>(observer => { Console.WriteLine("# Create method called."); // 引数の IObserver<int>に対して On****メソッドを呼ぶ observer.OnNext(1); observer.OnNext(2); observer.OnNext(3); observer.OnCompleted(); // Dispose が呼ばれた時の処理を返す。 // リソースを確保していた場合は、ここで解放すると良い。 return () => Console.WriteLine("Disposable action"); }); // 購読 var subscription1 = source.Subscribe( i => Console.WriteLine("OnNext({0})", i), ex => Console.WriteLine("OnError({0})", ex.Message), () => Console.WriteLine("Completed()")); var subscription2 = source.Subscribe( i => Console.WriteLine("OnNext({0})", i), ex => Console.WriteLine("OnError({0})", ex.Message), () => Console.WriteLine("Completed()")); // 購読停止(この場合意味はない) Console.WriteLine("# Dispose method call."); subscription1.Dispose(); 17
  • 25. subscription2.Dispose(); 実行結果は、下記のようになります。 ## CreateSample # Create method called. OnNext(1) OnNext(2) OnNext(3) Completed() Disposable action # Create method called. OnNext(1) OnNext(2) OnNext(3) Completed() Disposable action # Dispose method call. 注意したいのは Disposable action の表示されているタ゗ミングです。通常の考えだと subscription1.Dispose();の呼び出しタ゗ミングで Disposable action と表示されるように思いま すが動作を確認すると Dispose メソッドを呼ぶ前に自動で呼び出されています。これは、 Completed の後で、もう購読していても値が来ないため Dispose が自動で行われていることを示 しています。 これまでのサンプルでも Dispose に特に意味がないと書いていたのはこのためです。 3.2.7. Observable.Throw メソッド 一連の基本的な IObservable<T>を作成するメソッドの締めくくりとして最後に Throw メソッド を紹介します。これは引数に例外を渡します。 疑似的にエラーを起こしたいときに使う以外に使用 方法が思いつきません。コード例を下記に示します。 // エラーを発行するだけの IObservable<int>を生成 var source = Observable.Throw<int>(new Exception("Error message")); // 購読 var subscription = source.Subscribe( i => Console.WriteLine("OnNext({0})", i), ex => Console.WriteLine("OnError({0})", ex.Message), () => Console.WriteLine("Completed()")); // 購読停止(この場合意味はない) subscription.Dispose(); 実行結果は下記のようになります。OnError が呼ばれているのがわかります。 OnError(Error message) 18
  • 26. 3.3. ここまでに紹介した IObservable<T>の動作 ここまで紹介してきた IObservable<T>は、全て下記のような特徴があります。 1. フゔクトリで発行する値を指定して IObservable<T>を作成する。 2. Subscribe が呼び出されると以下のような動きをする 1. 値を全て発行する 2. 終わったら OnCompleted を呼ぶ 3. 購読を解除する 3. Subscribe が行われる度に 2 の動作を行う。 この動作を表した図を以下に示します。 上記の図では OnError と二度目の Subscribe について書いていませんが、 基本的に OnError の時 には例外が IObserver<T>に通知されます。また、一度の Subscribe で IObservable<T>が空に なるように見えますがデータの流れを示すために空にしているだけで実際には再度 Subscribe を 行うと値が発行されます。 3.4. リソースの確保を伴う IObservable<T> ここでは、IObservable<T>を取得する際にリソースの確保を行うケースに使用できるフゔクト リメソッドについて説明します。 19
  • 27. 3.4.1. Observable.Uting メソッド Using メソッドは、 名前の通り using ブロックのようにリソースを確実に解放するために使用する メソッドになります。メソッドのシグネチャは、第一引数に Func<TResource>を渡して、リソ ースを確保するオブジェクトを作成する処理を指定します。TResource 型は IDisposable を実装 している必要があります。 第二引数に、 Func<TResource, IObservable<TSource>>を渡して、 リソースを使って IObservable<T>を取得する処理を指定します。実際には、外部リソースに依 存するものを使用する場合のコード例が適しているのですが、ここでのサンプルは、ダミーの IDisposable を実装した下記のようなクラスを使用して動作確認を行います。 // サンプルのダミーリソースクラス class SampleResource : IDisposable { // データを取得する public IObservable<string> GetData() { return Observable.Create<string>(o => { o.OnNext("one"); o.OnNext("two"); o.OnNext("three"); o.OnCompleted(); return Disposable.Empty; }); } // 解放処理 public void Dispose() { Console.WriteLine("Resource.Dispose called"); } } このクラスを使用して Using メソッドの動作確認を行います。Using メソッドの使用例を下記に 示します。 // SampleResource(IDisposable を実装)を使用してデータを取得する var source = Observable.Using( () => new SampleResource(), sr => sr.GetData()); // 購読 20
  • 28. source.Subscribe( i => Console.WriteLine("OnNext({0})", i), ex => Console.WriteLine("OnError({0})", ex.Message), () => Console.WriteLine("Completed()")); Using メソッドで SampleResource クラスの作成と、SampleResource クラスを使って IObservable<T>を取得しています。このコードの実行結果を下記に示します。 OnNext(one) OnNext(two) OnNext(three) Completed() Resource.Dispose called 実行結果からもわかるように、最後に、SampleResource クラスの Dispose が呼ばれていること がわかります。 3.5. 時間と共に値を発行する IObservable<T> ここでは時間と共に値を発行する IObservable<T>を返すフゔクトリメソッドを使って動作を確 認します。 3.5.1. 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(); 21
  • 29. // Observable が発行する値の購読を停止 Console.WriteLine("dispose method call."); subscription.Dispose(); // Dispose をすると値が発行されなくなる。 Console.WriteLine("please enter key..."); Console.ReadLine(); コメントにもある通り、 上記のコードは 3 秒後から 1 秒間隔で値を発行する IObservable<long> を作成して Subscribe で購読しています。そして、Console.ReadLine で待機しています。暫く 待っていると OnNext が発行されます。適当なタ゗ミングで Enter キーを押すと subscription.Dispose()が実行され、購読が解除されます。Dispose のあとは、OnNext が実行さ れないことを確認できます。実行結果を下記に示します。 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... Timer の実行゗メージを下図に示します。 22
  • 30. 3.5.2. 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 が実行されたあとに数秒間待機し て購読が停止していることを確認しています。 23
  • 31. 3.5.3. Observable.Generate メソッド 次は、3.2.4 でも使用した Generate メソッドを使用します。Generate メソッドには TimeSpan を受け取るオーバーロードがあり、これを使うことで指定した時間間隔で値を発行する IObservable<T>を作成できます。コード例を下記に示します。 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) 24
  • 32. 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 メソッドの処理を途中から購読しなくなります。 3.6. Cold な IObservable<T>と Hot な IObservable<T> ここまでに紹介した IObservable<T>のフゔクトリメソッドは全て共通の特徴があります。それ は複数回 Subscribe すると、それぞれの IObserver<T>に IObservable<T>が個別に値を発行し ます。IObservable<T>の作り方にもよりますが、基本的には同じ値が発行されていきます。文 章で説明するよりもコードの動作例で示します。 // 1 秒間隔で値を発行する IObservable<long>を作成する var source = Observable.Timer( TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)); // 購読 var subscription1 = source.Subscribe( i => Console.WriteLine("{0:yyyy/MM/dd HH:mm:ss.FFF} 1##OnNext({1})", DateTime.Now, i), ex => Console.WriteLine("1##OnError({0})", ex.Message), 25
  • 33. () => Console.WriteLine("1##Completed()")); // 3 秒後にもう一度購読 Thread.Sleep(3000); // 購読 var subscription2 = source.Subscribe( i => Console.WriteLine("{0:yyyy/MM/dd HH:mm:ss.FFF} 2##OnNext({1})", DateTime.Now, i), ex => Console.WriteLine("2##OnError({0})", ex.Message), () => Console.WriteLine("2##Completed()")); Console.ReadLine(); subscription1.Dispose(); subscription2.Dispose(); 上記のコードは 1 秒間隔で値を発行する IObservable<long>を作成し、 回 Subscribe したあと 1 に 3 秒待ってもう一度 Subscribe しています。この実行結果を下記に示します。 2011/11/07 23:05:01.883 1##OnNext(0) 2011/11/07 23:05:02.884 1##OnNext(1) 2011/11/07 23:05:03.879 1##OnNext(2) 2011/11/07 23:05:04.877 1##OnNext(3) 2011/11/07 23:05:04.893 2##OnNext(0) 2011/11/07 23:05:05.89 1##OnNext(4) 2011/11/07 23:05:05.894 2##OnNext(1) 2011/11/07 23:05:06.877 1##OnNext(5) 2011/11/07 23:05:06.892 2##OnNext(2) 2011/11/07 23:05:07.873 1##OnNext(6) 2011/11/07 23:05:07.894 2##OnNext(3) 最初に Subscribe した方には yyyy/MM/dd HH:mm:ss.FFF 1##OnNext(値)の形式で出力して います。二番目に Subscribe した方には yyyy/MM/dd HH:mm:ss.FFF 2##OnNext(値)の形式 で出力しています。これを見ると、最初に Subscribe したものと二回目に Subscribe したもので は、タ゗ムスタンプが微妙にずれていることから、 内部的には別のタ゗マーが割り当てられている ことが見て取れます。また、発行される値も Subscribe した時点で 0 からカウントされていて最 初に Subscribe したものと二回目に Subscribe したものの間に関係性は全くありません。このよ うに、Cold な Observable は「複数回 Subscribe した時に Observer 毎に独立した値を発行する」 という特徴があります。 では次に、Cold と対となるものとして Hot な IObservable<T>を見ていきます。Hot な Observable の代表として.NET 組み込みの Observer パターンである゗ベントから IObservable<T>を生成する Observable.FromEvent<TDelegate, TEventArgs>(…)というメ ソッドがあります。このメソッドのシグネチャを下記に示します。 26
  • 34. public static IObservable<TEventArgs> FromEvent<TDelegate, TEventArgs>( // Action<TEventArgs>から゗ベントハンドラの形へと変換する処理 // Action<TEventArgs>は Subscribe したときの OnNext の処理にあたる。 Func<Action<TEventArgs>, TDelegate> conversion, // ゗ベントハンドラを登録する処理 Action<TDelegate> addHandler, // ゗ベントハンドラの登録を解除する処理 Action<TDelegate> removeHandler) 今まで出てきたもののなかではかなり異質の引数ですが゗ベントハンドラの形にあったデリゲー トを作成してハンドラの登録処理と削除処理を渡します。あとは IObservable<TEventArgs>を Subscribe したタ゗ミングや Dispose したタ゗ミングで適切に゗ベントの登録・登録解除が行わ れます。 自前でやると゗ベントハンドラの登録解除は忘れがちな処理なので地味に有りがたい機能 です。コード例を下記に示します。 // 1 秒間隔で値を発行する Timer var timer = new System.Timers.Timer(1000); var source = Observable.FromEvent<ElapsedEventHandler, ElapsedEventArgs>( h => (s, e) => h(e), h => timer.Elapsed += h, h => timer.Elapsed -= h); // タ゗マー開始 timer.Start(); // 購読 var subscription1 = source.Subscribe( e => Console.WriteLine("{0:yyyy/MM/dd HH:mm:ss.FFF} 1##OnNext({1:yyyy/MM/dd HH:mm:ss.FFF})",DateTime.Now, e.SignalTime), ex => Console.WriteLine("1##OnError({0})", ex.Message), () => Console.WriteLine("1##Completed()")); // 3 秒後にもう一度購読 Thread.Sleep(3000); // 購読 var subscription2 = source.Subscribe( e => Console.WriteLine("{0:yyyy/MM/dd HH:mm:ss.FFF} 2##OnNext({1:yyyy/MM/dd HH:mm:ss.FFF})",DateTime.Now, e.SignalTime), ex => Console.WriteLine("2##OnError({0})", ex.Message), () => Console.WriteLine("2##Completed()")); 27
  • 35. Console.ReadLine(); subscription1.Dispose(); subscription2.Dispose(); timer.Stop(); Cold な Observable で示した処理と基本的には同じ処理を行っています。実行結果を下記に示し ます。 2011/11/07 23:37:41.146 1##OnNext(2011/11/07 23:37:41.146) 2011/11/07 23:37:42.16 1##OnNext(2011/11/07 23:37:42.16) 2011/11/07 23:37:43.174 1##OnNext(2011/11/07 23:37:43.174) ← ここと 2011/11/07 23:37:43.174 2##OnNext(2011/11/07 23:37:43.174) ← ここ 以下 2 つずつ同じ値が表示されてい る 2011/11/07 23:37:44.188 1##OnNext(2011/11/07 23:37:44.188) 2011/11/07 23:37:44.188 2##OnNext(2011/11/07 23:37:44.188) 2011/11/07 23:37:45.202 1##OnNext(2011/11/07 23:37:45.202) 2011/11/07 23:37:45.202 2##OnNext(2011/11/07 23:37:45.202) 2011/11/07 23:37:46.216 1##OnNext(2011/11/07 23:37:46.216) 2011/11/07 23:37:46.216 2##OnNext(2011/11/07 23:37:46.216) 上記の結果で興味深い点は、最初に Subscribe したものと、二番目に Subscribe したものの出力 結果のタ゗ムスタンプと、OnNext に渡ってきている値が同じという点です。 つまり、Hot な IObservable<T>とは Cold な IObservable<T>と違って「複数回 Subscribe し たときに、全ての Observer に同じタ゗ミングで同じ値を発行するもの」ということになります。 3.6.1. Observable.FromEvent メソッド では、Hot な IObservable<T>を作成するメソッドのトップバッターとして先ほど登場した FromEvent メソッドを紹介します。FromEvent メソッドのシグネチャは既に示したので、より 詳しく動作を確認するためのコードを下記に示します。 // ゗ベントを発行するクラス var eventSource = new EventSource(); var source = Observable.FromEvent<EventHandler, EventArgs>( h => (s, e) => h(e), // 普通は h => eventSource.Raised += h だけでいい h => { Console.WriteLine("add handler"); eventSource.Raised += h; }, // 普通は h => eventSource.Raised -= h だけでいい 28
  • 36. h => { Console.WriteLine("remove handler"); eventSource.Raised -= h; }); // 2 回購読 var subscription1 = source.Subscribe( i => Console.WriteLine("1##OnNext({0})", i), ex => Console.WriteLine("1##OnError({0})", ex.Message), () => Console.WriteLine("1##Completed()")); var subscription2 = source.Subscribe( i => Console.WriteLine("2##OnNext({0})", i), ex => Console.WriteLine("2##OnError({0})", ex.Message), () => Console.WriteLine("2##Completed()")); // 2 回呼び出してみる // 合計 4 回の OnNext が呼ばれるはず eventSource.OnRaised(); eventSource.OnRaised(); // Observable が発行する値の購読を停止 Console.WriteLine("dispose method call."); subscription1.Dispose(); subscription2.Dispose(); この例で使用している EventSource クラスは、Raised という゗ベントと OnRaised という゗ベ ントを発行するメソッドだけを持ったクラスで下記のように定義しています。 // ゗ベント発行クラス class EventSource { public event EventHandler Raised; public void OnRaised() { var h = this.Raised; if (h != null) { h(this, EventArgs.Empty); 29
  • 37. } } } このコードの実行結果を下記に示します。 add handler add handler 1##OnNext(System.EventArgs) 2##OnNext(System.EventArgs) 1##OnNext(System.EventArgs) 2##OnNext(System.EventArgs) dispose method call. remove handler remove handler FromEvent メソッドの゗ベントハンドラ登録処理と゗ベントハンドラの登録解除処理にログを出 力するように仕込んだものが表示されています。 このことから、Dispose を呼ぶときちんと゗ベン トハンドラの登録解除が行われることがわかります。また、゗ベントが発行されたタ゗ミングで 2 つ登録した Observer の両方に対して通知がいっていることも確認できます。 3.6.2. Observable.Start メソッド 次に、簡単にバックグラウンドの処理を記述できる Start メソッドについて説明します。Start メ ソッドは Action か Func<T>を引数に受け取り IObservable<Unit>か IObservable<T>を返し ます。引数で受け取ったデリゲートの処理が終わると IObservable から結果が発行されます。コ ード例を下記に示します。 // バックグラウンドで処理を開始 var source = Observable.Start(() => { Console.WriteLine("background task start."); Thread.Sleep(2000); Console.WriteLine("background task end."); return 1; }); // 購読 Console.WriteLine("subscribe1"); var subscription1 = source.Subscribe( i => Console.WriteLine("1##OnNext({0})", i), ex => Console.WriteLine("1##OnError({0})", ex.Message), () => Console.WriteLine("1##Completed()")); 30
  • 38. // 処理が確実に終わるように 5 秒待つ Console.WriteLine("sleep 5sec."); Thread.Sleep(5000); // Observable が発行する値の購読を停止 Console.WriteLine("dispose method call."); subscription1.Dispose(); // 購読 Console.WriteLine("subscribe2"); var subscription2 = source.Subscribe( i => Console.WriteLine("2##OnNext({0})", i), ex => Console.WriteLine("2##OnError({0})", ex.Message), () => Console.WriteLine("2##Completed()")); subscription2.Dispose(); このサンプルで特徴的なのが、 Start メソッド内の処理が 2 秒で終わるにも関わらず 5 秒スリープ した後に Subscribe をしている点です。通常の感覚では、既に処理が完了して値が発行された後 なので Subscribe しても何も起きないと考えられます。しかし、Start メソッドの戻り値の IObservable<T>は最後の処理結果をキャッシュしています。 そのため、Subscribe されるとキャ ッシュしている値と OnCompleted を発行します。 この例の実行結果では、最初の Subscribe と二回目の Subscribe それぞれで、OnNext と OnCompleted の処理が呼ばれます。実行結果を下記に示します。 subscribe1 sleep 5sec. ← ここで 5 秒スリープしている background task start. background task end. 1##OnNext(1) 1##Completed() dispose method call. subscribe2 ← このタ゗ミングでは Start メソッドの処理は終了している 2##OnNext(1) ← OnNext と OnCompleted が通知される 2##Completed() このことから、Start メソッドで作成する IObservable<T>は、Start メソッドが完了するまでは Hot な Observable で処理が終了したあとは Cold な Observable になるという 2 面性をもつとい う特徴があることが確認できます。 31
  • 39. 3.6.3. Observable.ToAsync メソッド 次は、ToAsync メソッドを紹介します。このメソッドも Start メソッドと同様に重たい処理をバ ックグラウンドでやるために使用できます。Start メソッドとの違いは ToAsync の戻り値にあら われています。シグネチャを下記に示します。 public static Func<IObservable<T>> ToAsync<T>(Func<T> function) 引数に重たいことをやる処理を渡して、戻り値が IObservable<T>を返すデリゲートになってい ます。この戻り値のデリゲートを呼び出すことで ToAsync の引数に渡した処理がはじめて実行さ れます。Start は、Start メソッドを呼び出した直後から処理が開始されましたが、ToAsync を使 うと処理の開始のタ゗ミングを柔軟に制御できます。 ここで示したメソッドのシグネチャは数十個あるオーバーロードの 1 つになります。ToAsync に はほかにも戻り値が無いケースや引数が大量にあるケースに備えて膨大な数のオーバーロードが あります。完全なオーバーロードのリストについては下記の MSDN のリフゔレンスを参照してく ださい。 Observable.ToAsync Method : http://msdn.microsoft.com/en-us/library/system.reactive.linq.observable.toasync(v=VS. 103).aspx コード例を下記に示します。 // 戻り値は Func<IObservable<T>> var source = Observable.ToAsync(() => { Console.WriteLine("background task start."); Thread.Sleep(2000); Console.WriteLine("background task end."); return 1; }); // ToAsync はデリゲートを返すので Invoke() or ()をしないと処理が開始されない Console.WriteLine("source() call."); var invokedSource = source.Invoke(); var subscription1 = invokedSource.Subscribe( i => Console.WriteLine("1##OnNext({0})", i), ex => Console.WriteLine("1##OnError({0})", ex.Message), () => Console.WriteLine("1##Completed()")); // 処理が確実に終わるように 5 秒待つ Console.WriteLine("sleep 5sec."); Thread.Sleep(5000); 32
  • 40. // Observable が発行する値の購読を停止 Console.WriteLine("dispose method call."); subscription1.Dispose(); // 購読 Console.WriteLine("subscribe2"); var subscription2 = invokedSource.Subscribe( i => Console.WriteLine("2##OnNext({0})", i), ex => Console.WriteLine("2##OnError({0})", ex.Message), () => Console.WriteLine("2##Completed()")); subscription2.Dispose(); ポ゗ントは、ToAsync の戻り値に対して Invoke をしているところです。ここで初めて ToAsync に渡した処理の実行がはじまります。実行結果を下記に示します。 source() call. background task start. sleep 5sec. background task end. 1##OnNext(1) 1##Completed() dispose method call. subscribe2 2##OnNext(1) 2##Completed() ここでも Start メソッドの例と同じように ToAsync の処理が終わった後に Subscribe しているに も関わらず OnNext と OnCompleted が呼ばれていることがわかります。非同期で処理を行う IObservable<T>は全体的にこのような動きを行うので覚えておきましょう。 3.6.4. Observable.FromAsyncPattern メソッド これで、一連のフゔクトリメソッドの紹介は最後になります。 最後を飾るのは FromAsyncPattern メソッドです。このメソッドは名前が示す通り.NET Framework で使われている非同期呼び出し のパターンから IObservable<T>を作成します。 // 重たい処理 Func<int, int, int> asyncProcess = (x, y) => { Console.WriteLine("process start."); Thread.Sleep(2000); Console.WriteLine("process end."); 33
  • 41. return x + y; }; // 因みに非同期呼び出しは普通に書くとこんな感じ // asyncProcess.BeginInvoke( // 10, 2, // ar => // { // var ret = asyncProcess.EndInvoke(ar); // // do something // }, // null); var asyncPattern = Observable.FromAsyncPattern<int, int, int>( asyncProcess.BeginInvoke, asyncProcess.EndInvoke); var source = asyncPattern(10, 2); // 処理中に購読開始 Console.WriteLine("subscribe2"); var subscription1 = source.Subscribe( i => Console.WriteLine("1##OnNext({0})", i), ex => Console.WriteLine("1##OnError({0})", ex.Message), () => Console.WriteLine("1##Completed()")); // 確実に処理が終わるように 5 秒待つ Console.WriteLine("sleep 5sec"); Thread.Sleep(5000); // Observable が発行する値の購読を停止 Console.WriteLine("dispose method call."); subscription1.Dispose(); // 処理が完了したあとに購読 Console.WriteLine("subscribe2"); var subscription2 = source.Subscribe( i => Console.WriteLine("2##OnNext({0})", i), ex => Console.WriteLine("2##OnError({0})", ex.Message), 34
  • 42. () => Console.WriteLine("2##Completed()")); // 購読解除 Console.WriteLine("dispose method call."); subscription2.Dispose(); 普通はコールバックで書く非同期呼び出しを IObservable<T>にラッピングします。このメソッ ドも ToAsync と同様に戻り値がデリゲートなので、デリゲートを呼び出すことで非同期処理が開 始されます。実行結果を下記に示します。 process start. subscribe2 sleep 5sec process end. 1##OnNext(12) 1##Completed() dispose method call. subscribe2 2##OnNext(12) 2##Completed() dispose method call. ここでも、処理が終わった後に Subscribe をしても OnNext と OnCompleted が呼ばれているこ とがわかります。 4. IObservable の拡張メソッド ここまで IObservable<T>を作成するための様々なフゔクトリメソッドを見てきました。ここで は、視点を変えて IObservable<T>を作成したあとに使用できる IObservable<T>に定義された 拡張メソッドを紹介します。 4.1. LINQ のメソッド IObservable<T>の拡張メソッドも、 ほとんどが System.Reactive.Linq.Observable クラスに定 義されています。その中でも LINQ でお馴染みの Where や Select メソッドも含まれています。 LINQ のメソッドは IObservable<T>が発行した値に対して Where でフゖルタリングしたり Select で変換したりできます。下図は、その゗メージを表しています。 35
  • 43. 下図は Where でフゖルタリングされた場合を表しています。Where でフゖルタリングされた場 合は Select や Subscribe まで処理はいきません。 実際にコードで動きを確認してみます。 // 値を発行するための Subject var subject = new Subject<int>(); // AsObservable で IObservable<T>に変換(ゕップキャストで Subject<T>に戻せない var source = subject.AsObservable(); // 普通に Subscribe source.Subscribe( value => Console.WriteLine("1##OnNext({0})", value), ex => Console.WriteLine(ex.Message), () => Console.WriteLine("1##OnCompleted()")); // 奇数のみ通すようにフゖルタリングして source.Where(i => i % 2 == 1) // 文字列に加工して .Select(i => i + "は奇数です") // 表示する 36
  • 44. .Subscribe( value => Console.WriteLine("2##OnNext({0})", value), ex => Console.WriteLine(ex.Message), () => Console.WriteLine("2##OnCompleted()")); // 1~10 の値を subject に対して発行する Observable.Range(1, 10).ForEach(i => subject.OnNext(i)); // 完了通知を行う subject.OnCompleted(); 上記のコードでは、1~10 の値を Subject<T>を使って発行しています。Subject<T>は、 AsObservable メソッドで IObservable<T>に変換できます。AsObservable をしなくても Subject<T>クラスは IObservable<T>を継承しているので差支えはないのですが、純粋な IObservable<T>に、なんとなくしたかったのでこの例では変換しています。通常は、内部に Subject<T>クラスを抱えたクラスが外部に IObservable<T>を公開するときに、ダウンキャス トされても Subject<T>型に戻せない IObservable<T>を返すために使用します。 その他に、今回初登場のメソッドとして ForEach メソッドがあります。これは引数に渡された Action<T>を、IObservable<T>から発行された値を引数に渡して使用します。平たく言うと for ループです。ここでは 1~10 の値を Observable.Range で作成して ForEach で Subject<T>に 流し込んでいます。 今回の本題である拡張メソッドは Where メソッドと Select メソッドになります。Where メソッ ドは引数で渡した Func<T, bool>が true を返す要素のみを通します。Select メソッドは引数で 渡した Func<T, U>で値を変換します。上記の例では奇数以外の値をフゖルタリングして「X は 奇数です」という文字列に変換して、Subscribe 内で標準出力に出力しています。動作の違いを見 るために、Where や Select を使用しないで Subscribe もしています。 このプログラムの実行結果を下記に示します。 1##OnNext(1) 2##OnNext(1 は奇数です) 1##OnNext(2) 1##OnNext(3) 2##OnNext(3 は奇数です) 1##OnNext(4) 1##OnNext(5) 2##OnNext(5 は奇数です) 1##OnNext(6) 1##OnNext(7) 2##OnNext(7 は奇数です) 1##OnNext(8) 1##OnNext(9) 37
  • 45. 2##OnNext(9 は奇数です) 1##OnNext(10) 1##OnCompleted() 2##OnCompleted() 実行結果から、Where によるフゖルタリングが行われていることと、Select による変換が行われ ていることがわかると思います。 4.2. 単一の値を取得するメソッド ここでは、IObservable<T>のシーケンスから単一の値を取得するために利用するメソッドにつ いて説明します。 4.2.1. First メソッドと Last メソッド まず、最初の値を取得する First メソッドと、最後の値を取得する Last メソッドについて説明し ます。各メソッドのシグネチャは以下のようになります。 // First メソッド public static TSource First<T>( this IObservable<T> source ) // Last メソッド public static TSource Last<T>( this IObservable<T> source ) どちらのメソッドも IObservable<T>から T の値を取得します。First メソッドのコード例を下記 に示します。 // Observable を作成前のタ゗ムスタンプを表示 Console.WriteLine("Timestamp {0:yyyy/MM/dd HH:mm:ss.FFF}", DateTime.Now); var firstResult = Observable // 5 秒間隔で値を発行する .Interval(TimeSpan.FromSeconds(5)) .Select(i => "value is " + i) // 最初の値を取得 .First(); // First の実行が終わった後のタ゗ムスタンプを表示 Console.WriteLine("Timestamp {0:yyyy/MM/dd HH:mm:ss.FFF}", DateTime.Now); // 取得した値を表示 Console.WriteLine("firstResult: {0}", firstResult); 38