C#中如何观测可被覆盖的类实例内的响应式属性?
解决ReactiveProperty实例更新后嵌套订阅失效的问题
问题核心原因
你遇到的问题本质是直接绑定了旧实例的Observable引用:当ClassAInstance更新为新的ClassA对象时,原本的onValueInClassAChanged仍然指向旧ClassA实例的SomeVariable,自然不会响应新实例的变量变化。
最优解决方案(自动跟踪实例变更)
利用Rx的Select+Switch操作符,实现自动跟踪最新实例的嵌套Observable,无需手动解绑/重绑,这是Rx处理此类嵌套订阅场景的标准做法。
修正后的完整代码
using UnityEngine; using UniRx; public class ServiceA : MonoBehaviour { public ReactiveProperty<ClassA> ClassAInstance = new ReactiveProperty<ClassA>(); // 修正:自动跟随ClassA实例更新,绑定最新的SomeVariable public IObservable<ClassA> onClassAChanged => ClassAInstance; public IObservable<int> onValueInClassAChanged => ClassAInstance .Where(instance => instance != null) // 过滤空实例,避免空引用异常 .Select(instance => instance.SomeVariable) // 转换为当前实例的SomeVariable Observable .Switch(); // 自动切换到最新Observable,取消旧实例的订阅 private void Start() { // 订阅ClassA实例变更事件 onClassAChanged.Subscribe(instance => { Debug.Log($"ClassA实例已更新,ID: {instance.GetInstanceID()}"); }).AddTo(this); // 订阅嵌套变量变更,自动跟随实例更新 onValueInClassAChanged.Subscribe(value => { Debug.Log($"SomeVariable更新为: {value}"); }).AddTo(this); // 测试逻辑:更新实例并修改变量 ClassAInstance.Value = new ClassA(); ClassAInstance.Value.SomeVariable.Value = 5; // 再次更新实例,验证订阅是否生效 ClassAInstance.Value = new ClassA(); ClassAInstance.Value.SomeVariable.Value = 10; } } public class ClassA : MonoBehaviour { public ReactiveProperty<int> SomeVariable = new ReactiveProperty<int>(0); }
关键代码解释
Where(instance => instance != null):避免ClassAInstance为null时触发空引用异常Select(instance => instance.SomeVariable):每当ClassAInstance发出新实例,就获取该实例的SomeVariableObservableSwitch():自动取消对旧实例SomeVariable的订阅,转而订阅新实例的SomeVariable,实现无缝切换
手动重绑方案(不推荐,仅作参考)
如果一定要手动处理重绑,需要维护订阅对象的生命周期,在实例变更时先取消旧订阅,再订阅新实例的变量:
using UnityEngine; using UniRx; public class ServiceA : MonoBehaviour { public ReactiveProperty<ClassA> ClassAInstance = new ReactiveProperty<ClassA>(); public IObservable<ClassA> onClassAChanged => ClassAInstance; private IDisposable _valueSubscription; private void Start() { onClassAChanged.Subscribe(instance => { // 取消旧订阅 _valueSubscription?.Dispose(); // 订阅新实例的变量 _valueSubscription = instance?.SomeVariable.Subscribe(value => { Debug.Log($"SomeVariable更新为: {value}"); }).AddTo(this); }).AddTo(this); // 测试逻辑... } private void OnDestroy() { // 销毁时确保取消所有订阅,防止内存泄漏 _valueSubscription?.Dispose(); } }
这种方式需要手动管理订阅生命周期,容易遗漏导致内存泄漏,远不如Switch操作符的方案优雅。
内容的提问来源于stack exchange,提问作者yean
相关产品推荐
相关产品推荐

