Defer
1. 概要
Defer は、Observable の生成を購読時まで遅延させるファクトリメソッドです。購読されるたびにファクトリ関数が呼び出され、新しい Observable が生成されます。
副作用を持つ Observable の生成を購読時まで遅延させたい場合や、購読のたびに最新の状態に基づいて Observable を構築したい場合に使用します。
2. シグネチャ
csharp
public static Observable<T> Defer<T>(Func<Observable<T>> observableFactory, bool rawObserver = false)observableFactory は購読のたびに呼び出されます。各購読者は独立した Observable インスタンスを受け取ります。
rawObserver は通常 false のまま使います。true にすると observer.Wrap() による中継を省き、下流の Observer<T> を直接使います。詳しい違いは rawObserver を参照してください。
csharp
Observable.Defer(() => Observable.Return(DateTime.Now))3. マーブルダイアグラム
購読のたびにファクトリ関数が呼び出され、生成された Observable のシーケンスがそのまま転送されます。各購読者は独立したシーケンスを受け取ります。
4. サンプルコード
csharp
using R3;
// === 購読時に最新の値を取得 ===
// Defer なし: Observable 生成時の時刻が固定される
var eager = Observable.Return(DateTime.Now);
// Defer あり: 購読するたびに現在時刻を取得
var deferred = Observable.Defer(() => Observable.Return(DateTime.Now));
await Task.Delay(1000);
deferred.Subscribe(x => Console.WriteLine($"1 回目: {x:HH:mm:ss.fff}"));
await Task.Delay(1000);
deferred.Subscribe(x => Console.WriteLine($"2 回目: {x:HH:mm:ss.fff}"));
// 出力例: 1 回目: 12:00:01.000
// 出力例: 2 回目: 12:00:02.000(購読のたびに最新の時刻)
// === 副作用の遅延実行 ===
int counter = 0;
var deferred2 = Observable.Defer(() =>
{
counter++;
Console.WriteLine($"ファクトリ呼び出し #{counter}");
return Observable.Return(counter);
});
// ファクトリはまだ呼ばれていない
Console.WriteLine($"購読前: counter = {counter}");
// 出力: 購読前: counter = 0
deferred2.Subscribe(x => Console.WriteLine($"値: {x}"));
// 出力: ファクトリ呼び出し #1
// 出力: 値: 1
deferred2.Subscribe(x => Console.WriteLine($"値: {x}"));
// 出力: ファクトリ呼び出し #2
// 出力: 値: 25. 補足
Create との違い
Create は値の発行ロジックそのものを Observer<T> 経由で記述します。Defer は既存の Observable ファクトリの実行を購読時まで遅延させるだけであり、内部の Observable に値の発行を委ねます。
値の生成ロジックを一から記述したい場合は Create を、既存の Observable 生成メソッドの実行を遅延させたい場合は Defer を使用してください。