【Unity】【UniRx】Observable.Deferで購読まで処理を遅らせる

Observable.Deferで購読まで処理を遅らせる方法です。

Defer?

Observable.Defer()は他のObservableを返すActionを引数に取ります。
そして、Subscribe()されたときにはじめてその引数のActionのObservableを生成します。

はいよくわからないので具体例です。

具体例

まず、こんな感じのストリームを作ります。
期待している挙動は「Aを押したときに現在時間が表示される」です。

// 何回Aを押してもStart時点の時間がログとして吐かれる
var currentTimeStream   = Observable.Return(System.DateTime.Now);
var inputStream         = Observable
    .EveryUpdate()
    .Where(_ => Input.GetKeyDown(KeyCode.A))
    .SelectMany(_ => currentTimeStream)
    .Subscribe(x => Debug.Log(x));

しかしObservable.Returnは作られた時点で処理を行うため、
上記のソースコードは何回クリックしてもStart時点の時間が表示され続けます。

そこで、Observable.Deferを使って次のように書き換えます。

// DeferでObservableを囲む
var currentTimeStream   = Observable.Defer(() => Observable.Return(System.DateTime.Now));
var inputStream         = Observable
    .EveryUpdate()
    .Where(_ => Input.GetKeyDown(KeyCode.A))
    .SelectMany(_ => currentTimeStream)
    .Subscribe(x => Debug.Log(x));

Observable.Defer()はSelectManyによりSubscribeされるたびにObservable.Returnを生成するため、現在時刻を得られるようになります。