Rx.NET 7.0 拆分 Windows UI 支持,大幅缩减部署体积

Rx.NET 7.0 发布,将 Windows UI 集成拆分为独立包,解决自包含部署体积膨胀问题。本文解读改动细节、影响及升级建议,适合 .NET 开发者参考。
背景:Rx.NET 的维护与现代化
Rx.NET(Reactive Extensions for .NET)提供了基于 IObservable 的响应式编程模型,以及丰富的操作符来组合异步和事件驱动数据流。自 2023 年 1 月英国公司 endjin 接手维护以来,团队主要聚焦于现代化改造和偿还技术债务,而非盲目增加新功能。7.0 版本延续了这一思路,核心改动聚焦于一个关键问题:Windows 应用部署体积的优化。
问题:自包含部署中的“隐形负担”
在 .NET 开发中,自包含部署(self-contained)和 Native AOT 是常见的发布方式,它们能提升应用启动速度和部署便捷性。然而,当项目同时使用 Windows 特定目标框架(如 net8.0-windows10.0.19041)并引用 System.Reactive 时,即使应用完全未使用 WPF 或 Windows Forms,构建系统仍可能将完整的 UI 框架打包进最终产物。
根据 endjin 的数据,这种“捆绑”带来的额外体积相当可观:
- 不启用裁剪时,约 90 MB;
- 启用裁剪后,约 47 MB;
- 使用 Native AOT 构建,约 11 MB。
对于追求轻量部署的开发者来说,这显然是不可接受的。
解决方案:拆分 UI 集成到独立 NuGet 包
Rx.NET 7.0 将原先集中在 System.Reactive 中的 Windows UI 相关功能拆分为四个独立包:
System.Reactive.Windows.FormsSystem.Reactive.WpfSystem.Reactive.WindowsRuntimeSystem.Reactive.Uwp
这意味着,升级后如果你确实需要使用这些 UI 集成能力(例如在 WPF 中处理事件流),必须显式添加对应的 NuGet 包。而对于大多数只使用核心 Rx 功能的项目,无需修改任何源代码,部署体积就能明显瘦身。
兼容性与破坏性变更
为了照顾现有用户,维护团队尽量保持了二进制兼容性。旧版 UI API 仍保留在运行时程序集中,只是从引用程序集中移除。这意味着:
- 使用 Rx.NET 6.1 编译的组件理论上仍可继续运行;
- 但重新编译的应用若未添加对应包,将无法“不知不觉”地依赖 Windows UI 功能,编译时会报错,从而提醒开发者显式引用。
此外,7.0 还引入了一个 Analyzer,能检测受影响的源代码,并提示需要添加哪个包,进一步降低迁移成本。
当然,版本升级总会伴随破坏性变更:
- 不再支持 .NET 6 和 .NET 7,但继续支持 .NET 8、.NET 9、.NET 10、.NET Framework 4.7.2、.NET Standard 2.0 和 UWP。
- 修正了
OfType操作符的可空性标注(nullability annotations)。虽然运行时行为未变,但方法签名发生了变化,根据语义化版本规则,这需要提升主版本号。
特殊情况:packages.config 用户需注意
对于仍使用旧式 packages.config 机制的项目,由于该格式无法区分 NuGet 的 ref 和 lib 资产,即使没有显式引用新 UI 包,仍可能看到这些 UI API。维护团队并不支持这种配置,并可能在未来移除相关兼容代码。建议这类项目尽快迁移到 PackageReference。
社区反馈与未来展望
此前,Rx.NET 用户已多次反馈 Windows 特定打包问题,以及项目对现代 .NET 部署模型(如裁剪、AOT)的适应度。7.0 发布后,公开讨论尚不充分,但 endjin 表示,接手时制定的路线图主要目标已达成。后续工作可能包括:
- 进一步减少内存分配;
- 引入代码生成;
- 探索对类似 ref 元素的支持;
- 增加更多操作符。
升级建议
对于 .NET 开发者,升级到 Rx.NET 7.0 时建议:
- 检查项目是否使用 Windows UI 集成(如 WPF、WinForms),若有则添加对应 NuGet 包;
- 若无,直接升级,享受部署体积缩减;
- 关注 Analyzer 提示,确保代码正确迁移;
- 尽快摆脱 packages.config,避免兼容性问题。
Rx.NET 7.0 已可从 NuGet 获取,详细设计和后续计划可参考 GitHub 仓库。