Skip to content

EveryValueChanged

1. 概要

EveryValueChanged は、対象オブジェクトのプロパティをフレームごとにポーリングし、値が変化したときにその新しい値を発行するファクトリメソッドです。

購読時に現在の値を 1 回発行し、その後は前回値と異なる値になったフレームで新しい値を発行します。監視は CancellationToken のキャンセル、または購読の破棄によって終了します。

注意: TSource は参照型(class)である必要があります。

2. シグネチャ

基本(既定の FrameProvider)

csharp
public static Observable<TProperty> EveryValueChanged<TSource, TProperty>(TSource source, Func<TSource, TProperty> propertySelector, CancellationToken cancellationToken = default)
    where TSource : class

既定の FrameProviderObservableSystem.DefaultFrameProvider)を使って毎フレーム値をチェックします。

csharp
Observable.EveryValueChanged(player, p => p.Health)

FrameProvider 指定

csharp
public static Observable<TProperty> EveryValueChanged<TSource, TProperty>(TSource source, Func<TSource, TProperty> propertySelector, FrameProvider frameProvider, CancellationToken cancellationToken = default)
    where TSource : class

カスタムの FrameProvider を指定して、ポーリングのタイミングを制御します。

csharp
Observable.EveryValueChanged(player, p => p.Health, customFrameProvider)

EqualityComparer 指定

csharp
public static Observable<TProperty> EveryValueChanged<TSource, TProperty>(TSource source, Func<TSource, TProperty> propertySelector, EqualityComparer<TProperty> equalityComparer, CancellationToken cancellationToken = default)
    where TSource : class

値の比較に使用する EqualityComparer<TProperty> を指定します。既定では EqualityComparer<TProperty>.Default が使われます。

FrameProvider + EqualityComparer 指定

csharp
public static Observable<TProperty> EveryValueChanged<TSource, TProperty>(TSource source, Func<TSource, TProperty> propertySelector, FrameProvider frameProvider, EqualityComparer<TProperty> equalityComparer, CancellationToken cancellationToken = default)
    where TSource : class

FrameProviderEqualityComparer の両方を指定する完全版です。

オーバーロードの使い分け

オーバーロード使う場面
EveryValueChanged(source, selector)既定設定でプロパティ変化を監視する
... , frameProvider)ポーリングのフレームプロバイダーをカスタマイズしたい
... , equalityComparer)値の等価比較をカスタマイズしたい
... , frameProvider, equalityComparer)両方をカスタマイズしたい

3. マーブルダイアグラム

EveryValueChanged のマーブルダイアグラム

購読直後に現在の値が発行されます。その後は毎フレームプロパティの値がチェックされ、前回の値と異なる場合のみ新しい値が発行されます。CancellationToken がキャンセルされるとシーケンスが完了します。

4. サンプルコード

csharp
using R3;

// === ゲームオブジェクトのヘルス変化を監視 ===
var player = new Player { Health = 100 };

Observable.EveryValueChanged(player, p => p.Health)
    .Subscribe(hp => Console.WriteLine($"HP: {hp}"));
// Health が変化するたびに出力:
// HP: 100(初回値)
// HP: 80(ダメージを受けた)
// HP: 50(さらにダメージ)

// === Transform の位置変化を監視(Unity 向け) ===
// Observable.EveryValueChanged(transform, t => t.position)
//     .Subscribe(pos => Debug.Log($"位置: {pos}"));

// === カスタム EqualityComparer を使用 ===
var sensor = new TemperatureSensor();

Observable.EveryValueChanged(
        sensor,
        s => s.Temperature,
        EqualityComparer<double>.Create(
            (a, b) => Math.Abs(a - b) < 0.5,  // 0.5 度未満の変化は無視
            x => x.GetHashCode()))
    .Subscribe(temp => Console.WriteLine($"温度: {temp:F1}°C"));

5. 補足

ObservePropertyChanged との違い

ObservePropertyChangedINotifyPropertyChanged インターフェースを実装したオブジェクトに対して、プロパティ変更イベント(プッシュ型)で値の変化を検知します。イベント駆動のため毎フレームの比較コストが発生しません。

一方、EveryValueChanged は毎フレームのポーリング(プル型)で値を監視するため、INotifyPropertyChanged を実装していない任意のクラスに使用できます。ゲームオブジェクトや外部ライブラリの型など、変更通知の仕組みを持たないオブジェクトの監視に適しています。