管理人の技術ブログです。オブザーバーパターンの最後にもチラッと書きましたが、イベントはオブザーバーパターンの一実装です。イベントをIObservable<T>に乗せ、イベントに対応する処理を記述することができます。そこで今回は、イベントをIObservable<T>シーケンスに変換する方法について紹介します。IObservable<T>への変換Rxのライブラリには、イベントをIObservable<T>に変換するためのファクトリーメソッドがふたつ用意されています。Observable.FromEventメソッドとObservable.FromEventPatternメソッドです。簡単に使い方を確認してみましょう。以下にObservable.FromEventメソッドを使った簡単なサンプルを示します。キー入力が行われる度にKeyPressイベントを発行するだけの簡単なクラスを作成します。イベントの型にはAction<T>デリゲートを利用しています。Qが押下されたらループを抜けるようになっています。}}次に、Observable.FromEventメソッドを利用してKeyPressイベントの購読を行ないます。ジェネリックの型には、Action<T>デリゲートで受ける型を記述します。第1引数にはイベントの関連付け処理を、第2引数にはイベントの関連付け解除処理を記述します。OnNextメソッドの引数には、イベントの引数が流れてきます。結果(例)/*OnNext(A)OnNext(B)OnNext(C)OnNext(Enter)*/実行結果の通り、入力したキーが表示されるだけの簡単なサンプルです。お分かりかと思いますが、イベントをIObservable<T>に変換することで、これまでイベントハンドラとして記述していたものをOnNextメソッドで処理するように書き換えることができます。LINQスタイルでの記述で紹介したようにLINQスタイルの処理を間に挟むことができるので、通常のイベントよりも柔軟でわかりやすい処理ができるようになります。先の例ではAction<T>デリゲートに対する変換を行いました。Observable.FromEventメソッドにはいくつかのオーバーロードが用意されており、これらを利用すればEventHandler<T>デリゲートや独自デリゲートも変換可能です。先ほど挙げた例を少し変形したサンプルを下に示します。イベント引数を3つに分解しただけの簡単なものです。}}Observable.FromEventメソッドの別のオーバーロードを利用してIObservable<T>に変換します。今回は、イベントから渡される情報のうち、OnNextメソッドに通知したい情報がConsoleKey列挙体だけだったとして話を進めます。結果(例)/*OnNext(X)OnNext(Y)OnNext(Z)OnNext(Escape)*/Observable.FromEventメソッドに指定するひとつめのジェネリック型はイベントのデリゲート型です。ふたつめのジェネリック型には、OnNextメソッドで通知する情報の型を指定します。前の例では出て来なかった第1引数が、今回の重要なポイントです。イベント引数と通知する情報の型が異なるため、その差を埋めるためのコンバートを行っています。ふたつ続いているためわかりにくいですが、サンプルコードの中にもコメントで記載している通り、第1引数は省略記法となっています。第1引数で返したデリゲートが、第2/第3引数のhandlerB変数として渡され、イベントに関連付けられます。介してhandlerAデリデートが呼び出される、ということです。handlerAデリゲートの内部でOnNextメソッドの呼び出しが行われます。次に、Observable.FromEventメソッドに渡す各引数がどのように呼び出されるかを見てみます。先ほどの例をトレースするために画面出力を行うようにしたサンプルを示します。EventNotifierの内容は名前空間を除いて同じなので割愛します。OnNext(F4)*/上記の結果より、Subscribeメソッドによる関連付けのタイミングで第1引数と第2引数が連続して呼び出されていることがわかります。KeyPressイベント発生時に第1引数で返したデリゲートが実行されていることが確認できます。Disposeメソッドにより購読の解除を行うと、第3引数のデリゲートが呼び出され、イベント解除が行われます。何をやっているのか、何が起こっているのかはわかりにくく、あまり理解が進まない場合は、各引数にブレークポイントを置くなどして挙動をトレースしてみると良いです。私も最初は混乱していたのですが、トレースしたらすぐに理解できました。FromEventとFromEventPatternの違いObservable.FromEventPatternメソッドは、EventHandlerやEventHandler<T>に代表される典型的なイベントに特化したファクトリーメソッドです。基本的な使い方はObservable.FromEventメソッドとほとんど同じです。これにも多数のオーバーロードがあり、独自イベントハンドラへの対応も可能です。リフレクションを利用した記述も可能になっています。以下に簡単なサンプルを示します。イベント引数を定義します。ConsoleKeyInfo構造体をラップしているだけの非常に簡単なものです。}}次に、前の例で何度も出てきているEventNotifierのイベントを、EventHandler<T>を利用した形に書き換えます。}}準備ができたので、最後に利用するコードを記述します。今回はリフレクションを使用するオーバーロードを使ってみました。結果(例)/*OnNext(LeftArrow)OnNext(UpArrow)OnNext(RightArrow)OnNext(DownArrow)*/リフレクションを利用すると記述が非常に簡潔になりますが、そこはやはりリフレクションなので、イベント名を間違えたりしてもコンパイルエラーにならないという問題点があります。面倒がらずにリフレクションを利用しない書き方をするのが安全で良いと思います。OnNextメソッドの引数として渡されるデータはSystem.Reactive名前空間にあるEventPattern<T>クラスで、イベント引数であるSenderとEventArgsをひとまとめにして渡してくれます。今回の内容は、@neueccさんのblog記事にほぼほぼすべてに載っています。多くのオーバーロードに対する解説がされているので、非常に参考になります。@okazukiさんのblogではこれらを応用してドラッグ処理をしています。今回はイベントのIObservable<T>に変換する方法について見てきました。@okazukiさんのblog記事にもあるように、ドラッグ処理をひとつのシーケンスとして扱えたりするのは、もうある種の革命です。Rx万歳!次回は非同期処理をIObservable<T>シーケンスに変換する方法について触れてみたいと思います。7引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。