524 字
3 分钟
用 C# 写的桌面软件,用户要先装 C# 吗?
不用。这是个常见误解,但里面有几个概念值得分清楚。
用户其实不需要装”C#”
“C#“是语言,没法”装”。用户机器上可能需要的是 .NET Runtime——但是否需要、需要多大,取决于开发者选哪种部署方式。
类比:用 TypeScript 写 Electron 应用时,用户也不会被要求”装 TypeScript”或”装 Node.js”——因为 Electron 把 Chromium + Node.js 运行时直接打包进了 app。.NET 也有同样能力,只是开发者要主动选。
.NET 8 的四种部署方式
| 方式 | 用户要装 .NET 吗 | 包体积 | 启动 | 适合 |
|---|---|---|---|---|
| Framework-dependent (FDD) | 要 | ~5-10 MB | 一般 | 内部工具,环境可控 |
| FDD + Bootstrapper 自动装 | 不需手动 | app 5-10MB + 首次下载 ~70MB | 一般 | 联网装机场景 |
| Self-Contained (SCD) | 完全不需要 | ~60-80 MB | 一般 | 离线分发、企业部署 |
| Native AOT | 完全不需要 | ~10-30 MB | 极快 (<100ms) | 服务进程、CLI、对启动敏感的组件 |
跟 Electron 体积对比
Electron 现状: ~150 MBFDD + bootstrapper: ~10 MB + 首次下载 70 MBSelf-Contained: ~60-80 MBNative AOT: ~10-30 MB任何一种都比 Electron 小。NativeAOT 是数量级优势。
NativeAOT 的限制
不是免费午餐:
- 没有运行时反射(很多老库依赖反射,会编译失败或运行时报错)
- 没有动态加载程序集
- 不支持
System.Reflection.Emit - 不能用
dotnet ef这类依赖反射的工具运行时操作 - 编译时间长(几分钟级别)
所以一般规则:纯业务进程、服务、CLI 适合 AOT;带复杂 UI 框架(如 WinUI 3、WPF)的进程用 Self-Contained 更稳。
混合部署是常态
一个桌面产品通常多个进程组合:
EasyRemote.Service ← Native AOT (小、快、安全审计加分)EasyRemote.Helper ← Native AOT (桌面切换敏感,必须 <100ms 启动)EasyRemote.App (WinUI3) ← Self-Contained (WinUI3 用反射,AOT 兼容性不完善)libwebrtc.dll ← 静态库─────────────────────────────────────合计 ~115MB,完全离线可装,无任何"请先安装 X"对话框给用户的体感
双击 .msi → 装完 → 直接用。全程不联网、不弹运行时安装提示。和 Electron 一样甚至更好。
用 C# 写的桌面软件,用户要先装 C# 吗?
https://blog.cuixu.cn/posts/csharp-deployment-runtime-question/