概要

Rx ってのは Reactive Extensions のことだ!

なんて? ゴメンこの章はマジで興味がわかなかったのでホントにさらっと流す。せめて、自分なりに「Rx ってのは……」と説明できることを目標にするぜ。

 

Rx ってのは……

「イテレータ的なやつが値を返す瞬間、なんかしたいときに使うやつ。」かなあ。

  • Rx は IObservable<T> のもつ機能のことだ。
  • IObservable<T> ってのは前回の LINQ(『プログラミング C#』 その10 LINQ)の根幹をなす IEnumerable<T> に似てるが、ちょいと違うものだ。
    • IEnumerable<T> は受け身なシーケンスだ。ぼくらがなんか働きかけないとなんもしない。
    • IObservable<T> は受け身ではない。どういうことやねん。
  • どういうことかってーと、

 

IObservable ってこんなやつ

IObserver<T> とペアらしい。 .NET 4.0 からいるんだって。

// こいつは interface だから、こいつを継承して実装を作る流れなんだね。
// こいつの実装をオブザーバブルソースっていうんだって。
public interface IObservable<out T>
{
    // コイツの中に、「情報ソース」を書くのだ。
    //   こんな感じでな。→ observer.OnNext("わーわー");
    //     なんつーかぼくにだけ分かりやすいにように書けば、「yield してる」イメージ。
    IDisposable Subscribe(IObserver<T> observer);
    // そしてそのとき、↓の OnNext に書いた内容が実行されるって流れ。
}

// こいつの実装を↑の Subscribe にわたすんだね。
public interface IObserver<in T>
{
    // ↑に書いたとおり、 Observable が情報ソースを出すときに実行したいことを書く。
    void OnNext(T value);
    // Subscribe のシーケンスが終わったとき呼ばれるやつ。
    void OnCompleted();
    // エラーが起きたとき呼ばれるやつ。
    void OnError(Exception error);
}

ああ、 Python 用語で言えば、「イテレータが値を返してくるたびに何かしたい」ときに有効なやつか! なんか、メソッド実行前後にログを出力するデコレータとかを思い出す。でもアレはメソッドが対象だ。イテレータの next() 前後になんかするにはどうすればいいんだろ。ジェネレータにデコレータをつければいいんか……? わからん。

まあ落ち着け、↑のは interface だったから、実装を見てみよう。

// オブザーバーの実装。
class MySubscriber<T> : IObserver<T>
{
    // 情報ソースがなんか出してくるたびに「って出力してきたぜ」って print したいものとする。
    public void OnNext(T value)
    {
        Console.WriteLine($"Observable が {value} って出力してきたぜ。" );
    }

    public void OnCompleted()
    {
        Console.WriteLine("おわりやで。");
    }

    public void OnError(Exception exception)
    {
        Console.WriteLine($"エラーやで: {exception}");
    }
}

// コールドソースのオブザーバブルソース。
//   コールドソースってのはまあ、出力内容が固定みたいな意味じゃね?
class ColdSource : IObservable<string>
{
    public IDisposable Subscribe(IObserver<string> observer)
    {
        observer.OnNext("foo");
        observer.OnNext("bar");
        observer.OnCompleted();
        return EmptyDisposable.Instance;
    }

    private class EmptyDisposable : IDisposable
    {
        public static EmptyDisposable Instance = new EmptyDisposable();
        public void Dispose()
        {
        }
    }
}
// 実行するとこ。
public static void Main(string[] args)
{
    var source = new ColdSource();
    var subscriber = new MySubscriber<string>();
    source.Subscribe(subscriber);
}

実行するとこうなる。

Observable が foo って出力してきたぜ。
Observable が bar って出力してきたぜ。
おわりやで

うん、予想どおり。イテレータ(オブザーバブルソース)が値を返す(プッシュ)とき何かする(サブスクライバの OnNext を実行する)ってことだ。これだけだと対した意味合いを感じないけれど、「コールドソース」があるなら「ホットソース」もある。ホットソースは準備ができたときにサブスクライバに値を通知するものだ。

 

小休憩

まあ、興味がわかないからこれでいいや。