You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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发出新实例,就获取该实例的SomeVariable Observable
  • Switch():自动取消对旧实例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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 10:07:39