请添加图片描述

🐾 个人主页 🐾

阿松爱睡觉,横竖醒不来
🏅你可以不屠龙,但不能不磨剑🗡

一、C#自带接口

IObservableIObserver这是.NET框架内置的观察者模式标准实现,属于System命名空间。

核心接口

public interface IObservable<out T>
{
    IDisposable Subscribe(IObserver<T> observer);
}

public interface IObserver<in T>
{
    void OnNext(T value);      // 接收新数据
    void OnError(Exception error); // 错误处理
    void OnCompleted();        // 流结束通知
}

典型使用示例

// 自定义可观察序列
public class NumberObservable : IObservable<int>
{
    public IDisposable Subscribe(IObserver<int> observer)
    {
        for (int i = 0; i < 10; i++)
        {
            observer.OnNext(i); // 发射数据
            Thread.Sleep(500);
        }
        observer.OnCompleted(); // 结束序列
        return Disposable.Empty;
    }
}

// 观察者实现
public class ConsoleObserver : IObserver<int>
{
    public void OnNext(int value) => Console.WriteLine($"收到: {value}");
    public void OnError(Exception error) => Console.WriteLine($"错误: {error}");
    public void OnCompleted() => Console.WriteLine("完成");
}

// 使用
var observable = new NumberObservable();
var observer = new ConsoleObserver();
observable.Subscribe(observer);

特点分析

  • 优点

    • .NET标准库支持,无需额外依赖
    • 类型安全,泛型支持
    • 明确的错误和完成通知机制
  • 缺点

    • 功能相对基础,缺少操作符支持
    • 在Unity中使用不够直观
    • 需要手动实现很多功能

二、UniRx(Unity Reactive Extensions)

UniRx是专门为Unity优化的响应式编程扩展库,结合了Rx(Reactive Extensions)和Unity的生命周期管理。

核心组件

  • Observable:各种事件源创建方式
  • Observer:响应事件的处理器
  • Operators:丰富的操作符(Linq风格)
  • Schedulers:线程调度控制

典型使用示例

using UniRx;
using UnityEngine;

public class UniRxExample : MonoBehaviour
{
    void Start()
    {
        // 1. 鼠标点击事件流
        Observable.EveryUpdate()
            .Where(_ => Input.GetMouseButtonDown(0))
            .Subscribe(_ => Debug.Log("鼠标点击"));
        
        // 2. 协程转Observable
        Observable.FromCoroutine(LoadDataAsync)
            .Subscribe(result => Debug.Log($"加载完成: {result}"));
        
        // 3. UI绑定
        var inputField = GetComponent<TMP_InputField>();
        inputField.OnValueChangedAsObservable()
            .Throttle(TimeSpan.FromSeconds(0.5))
            .Subscribe(text => Debug.Log($"输入内容: {text}"));
    }
    
    IEnumerator LoadDataAsync()
    {
        yield return new WaitForSeconds(1);
        yield return "数据内容";
    }
}

核心优势

  • Unity集成

    • 自动与Unity生命周期绑定
    • 主线程安全,无需手动派发到主线程
    • 内置Update()Collision等Unity事件转Observable
  • 丰富操作符

    // 组合多个事件源
    Observable.CombineLatest(
        inputField1.OnValueChangedAsObservable(),
        inputField2.OnValueChangedAsObservable()
    ).Subscribe(values => {
        // 当任一输入框变化时触发
    });
    
    // 时间控制
    Observable.Timer(TimeSpan.FromSeconds(5))
        .Subscribe(_ => Debug.Log("5秒后执行"));
    
  • 异步处理简化

    // 替代协程的更强大方案
    Observable.FromCoroutine(LoadAsset)
        .Timeout(TimeSpan.FromSeconds(10))
        .Retry(3)
        .Subscribe(
            result => Debug.Log("成功"),
            ex => Debug.LogError($"失败: {ex}")
        );
    

UniRx进阶用法

1. 网络请求处理

ObservableWWW.Get("http://example.com/data.json")
    .Timeout(TimeSpan.FromSeconds(5))
    .Retry(3)
    .Subscribe(
        json => ParseData(json),
        error => Debug.LogError($"请求失败: {error}")
    );

2. 复杂事件流处理

var clickStream = Observable.EveryUpdate()
    .Where(_ => Input.GetMouseButtonDown(0));

var dragStream = Observable.EveryUpdate()
    .Where(_ => Input.GetMouseButton(0))
    .Select(_ => Input.mousePosition);

clickStream.Buffer(clickStream.Throttle(TimeSpan.FromMilliseconds(250)))
    .Where(clicks => clicks.Count >= 2)
    .Subscribe(_ => Debug.Log("双击检测"));

3. 状态管理

public class PlayerState
{
    public ReactiveProperty<int> Health { get; } = new ReactiveProperty<int>(100);
    public ReactiveProperty<bool> IsAlive { get; } = new ReactiveProperty<bool>(true);
    
    public PlayerState()
    {
        Health.Where(h => h <= 0)
            .Subscribe(_ => IsAlive.Value = false);
    }
}

// UI绑定
playerState.Health.SubscribeToText(healthText);

三、对比分析

特性IObservable/IObserverUniRx
平台支持所有.NET平台专为Unity优化
学习曲线较陡峭相对平缓
操作符支持需手动实现提供100+操作符
线程安全需手动处理自动主线程调度
Unity事件集成深度集成
生命周期管理需手动处理资源释放自动绑定GameObject生命周期
性能优化通用实现Unity特定优化

四、使用建议

  1. 何时使用标准IObservable

    • 开发非Unity的.NET应用程序
    • 需要最小化第三方依赖时
    • 已经有一套成熟的基础设施
  2. 何时选择UniRx

    • Unity项目开发
    • 需要处理复杂异步逻辑
    • 需要优雅的事件系统解决方案
    • 想要简化UI交互逻辑
  3. 性能注意事项

    • 避免创建过多不必要的Observable
    • 及时Dispose不再需要的订阅
    • 对于高频事件(如EveryUpdate),添加适当的Throttle/Debounce

UniRx将响应式编程的强大功能与Unity的特定需求完美结合,可以极大地提升Unity项目的代码组织和可维护性,特别适合处理复杂的异步逻辑和事件流。

结语

请添加图片描述

请添加图片描述

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐