Windows Dev. Site

Reactive Extensions

以前、「C# LINQのクエリ式」http://crossframe.iiv.jp/20130503247/ で少し触れたReactiveExtensionsについて、かなりたちましたがここでテストしてみたいと思います。

ReactiveExtensionsについて、多くの記事がある以下のサイトを参考にしました。

http://blog.okazuki.jp/entry/20120219/1329663635

特にここにある合成について興味があり、3つの値を監視して合成してみました。

環境 : Mono 4.2.0 / Mac OSX 10.10.5

https://www.nuget.org/でダウンロードしたnuget.exeで

mono nuget.exe install Rx-Main

を実行。インストールされる.dllファイルをプログラムファイルと同じパスにコピーして使用しました。

combine.cs

using System;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Reactive.Concurrency;

class Program {
    static void Main(string[] args) {

        var source1 = new Subject<string>();
        var source2 = new Subject<int>();
        var source3 = new Subject<int>();

        source1.CombineLatest(
            source2.Where(n => n % 2 == 0).Select(i => i * 10),
            (l, r) => string.Format("{0} | {1}", l, r))
        .CombineLatest(
            source3.Take(2),
            (l, r) => string.Format("{0} || {1}", l, r))
        .Subscribe(
            s => Console.WriteLine("* OnNext: {0}", s),
            () => Console.WriteLine("* OnCompleted"));

        Console.WriteLine("source1:'foo1'");
        source1.OnNext("foo1");
        Console.WriteLine("source1:'foo2'");
        source1.OnNext("foo2");

        Console.WriteLine("source2:22");
        source2.OnNext(22);

        Console.WriteLine("source3:311");
        source3.OnNext(311);
        Console.WriteLine("source3:312");
        source3.OnNext(312);
        Console.WriteLine("source3:313");
        source3.OnNext(313);

        Console.WriteLine("source1:'bar1'");
        source1.OnNext("bar1");
        Console.WriteLine("source2:23");
        source2.OnNext(23);
        Console.WriteLine("source2:24");
        source2.OnNext(24);

        Console.WriteLine("source1:Completed!");
        source1.OnCompleted();
        Console.WriteLine("source2:99");
        source2.OnNext(99);
        Console.WriteLine("source2: Completed!");
        source2.OnCompleted();

        Console.ReadLine();
    }
}

ビルドと実行

mcs combine.cs -r:System.Reactive.Core.dll,System.Reactive.Linq.dll,System.Reactive.Interfaces.dll
mono ./combine.exe

実行結果

source1:’foo1′
source1:’foo2′
source2:22
source3:311
* OnNext: foo2 | 220 || 311
source3:312
* OnNext: foo2 | 220 || 312
source3:313
source1:’bar1′
* OnNext: bar1 | 220 || 312
source2:23
source2:24
* OnNext: bar1 | 240 || 312
source1:Completed!
source2:99
source2: Completed!
* OnCompleted

リアクティブプログラムなのに、オブザーバという言葉がでてきませんが、SubjectクラスにはIObservableとIObserverの両方のインターフェースを実装されているようです。
監視対象の値が3つとも用意されたタイミングで、表示しています。最近のプログラムは非同期処理、関数型言語の文法の普及等により、プログラムの読み方が昔のように上から下に処理が流れていくような作りから、かなり変わってきたということをしみじみと感じます。