本日は UniRx の小ネタ枠です。
UniRx の ReactiveProperty でそれぞれ Class, Struct, Record での差分チェックの動作が分からず確認したので記事に残します。
ReactivePropertyの値の変更
UniRx の ReactiveProperty を使うと値の変更を検知して特定の処理を行うといったコードを簡単に記述することができます。
今回はの「値の変更」の検知条件について Class, Struct, Record での違いを確認しました。
以下のサンプルコードを作成しました。
bool 型の変数を持たせた各定義の値を代入しなおしたとき、bool 値が変化した場合のみ通知が発生するか否かを検証します。
・ReactivePropertyTest
using System.Collections; using System.Collections.Generic; using UnityEngine; using UniRx; public class ReactivePropertyTest : MonoBehaviour { /// <summary> /// Class /// </summary> private class CheckClass { public bool onoff; } /// <summary> /// Struct /// </summary> private struct CheckStruct { public bool onoff; } /// <summary> /// Record /// </summary> private record CheckRecord { public bool onoff; } // 各ReactiveProperty変数 private ReactiveProperty<CheckClass> checkClassProp = new ReactiveProperty<CheckClass>(new CheckClass()); private ReactiveProperty<CheckStruct> checkStructProp = new ReactiveProperty<CheckStruct>(new CheckStruct()); private ReactiveProperty<CheckRecord> checkRecordProp = new ReactiveProperty<CheckRecord>(new CheckRecord()); void Start() { // Class 変更検知時の処理 checkClassProp .Subscribe(checkstate => { Debug.Log($"CheckClass Changed! : {checkstate.onoff}"); }) .AddTo(this); // Struct 変更検知時の処理 checkStructProp .Subscribe(checkstate => { Debug.Log($"CheckStruct Changed! : {checkstate.onoff}"); }) .AddTo(this); // Record 変更検知時の処理 checkRecordProp .Subscribe(checkstate => { Debug.Log($"CheckRecord Changed! : {checkstate.onoff}"); }) .AddTo(this); } /// <summary> /// 全ての bool を True に変更 /// </summary> [ContextMenu("ON")] void ChangeOn() { ChangeStates(true); } /// <summary> /// 全ての bool を False に変更 /// </summary> [ContextMenu("OFF")] void ChangeOff() { ChangeStates(false); } void ChangeStates(bool isOnOff) { var checkClass = new CheckClass() { onoff = isOnOff }; checkClassProp.Value = checkClass; var checkStruct = new CheckStruct() { onoff = isOnOff }; checkStructProp.Value = checkStruct; var checkRecord = new CheckRecord() { onoff = isOnOff }; checkRecordProp.Value = checkRecord; } }
結果として以下のような動作となりました。
・false -> true への変化の場合、Class, Struct, Record 全てで通知が発生する
・false -> false への変化の場合、Class でのみ通知が発生する
仕組み
RectiveProperty のソースコードを確認すると値の変更チェックには Equals が利用されています。
Classの場合
Class の定義では Equeals の処理をオーバーライドしていない場合、参照先の比較が行われます。
false -> false の変更でも値を代入しなおしているため、参照先が変わっており、通知が発生しています。
Structの場合
Struct は値型のため、デフォルトで値の比較が行われます。
このため、false -> true の変更でのみ通知が発生しています。
Recordの場合
Record は参照型ですが、Equals の処理で値の比較が行われます。
このため、false -> true の変更でのみ通知が発生しています。
learn.microsoft.com