【Unity开发】C#的IObservable/IObserver与UniRx详解
·

目录
一、C#自带接口
IObservable 、IObserver这是.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/IObserver | UniRx |
|---|---|---|
| 平台支持 | 所有.NET平台 | 专为Unity优化 |
| 学习曲线 | 较陡峭 | 相对平缓 |
| 操作符支持 | 需手动实现 | 提供100+操作符 |
| 线程安全 | 需手动处理 | 自动主线程调度 |
| Unity事件集成 | 无 | 深度集成 |
| 生命周期管理 | 需手动处理资源释放 | 自动绑定GameObject生命周期 |
| 性能优化 | 通用实现 | Unity特定优化 |
四、使用建议
-
何时使用标准IObservable:
- 开发非Unity的.NET应用程序
- 需要最小化第三方依赖时
- 已经有一套成熟的基础设施
-
何时选择UniRx:
- Unity项目开发
- 需要处理复杂异步逻辑
- 需要优雅的事件系统解决方案
- 想要简化UI交互逻辑
-
性能注意事项:
- 避免创建过多不必要的Observable
- 及时Dispose不再需要的订阅
- 对于高频事件(如EveryUpdate),添加适当的Throttle/Debounce
UniRx将响应式编程的强大功能与Unity的特定需求完美结合,可以极大地提升Unity项目的代码组织和可维护性,特别适合处理复杂的异步逻辑和事件流。
结语


更多推荐


所有评论(0)