Rust 成为微软一线语言之后:谈谈 C# 与 Rust 的互补性 - 张善友

Rust 成为微软一线语言之后:谈谈 C# 与 Rust 的互补性 - 张善友

💡 原文中文,约1600字,阅读约需4分钟。
📝

内容提要

微软将Rust列为Tier-1语言,与C++、C#同级,但目标是替换有漏洞的C/C++存量代码,而非取代C#。C#擅长业务复杂度,Rust擅长资源与安全边界,二者互补:C#在上做编排,Rust在下做原生模块,通过显式FFI契约连接。对C#架构师而言,学会定义干净的边界契约比纠结是否学Rust更有价值。

🔎

延伸解读

Rust 的 Tier-1 定位:替换 C/C++,而非取代 C#

微软将 Rust 列为 Tier-1 语言,与 C++、C# 同级,但目标并非取代 C#。文章指出,微软引入 Rust 的首要目标是替换有漏洞的 C/C++ 存量代码,例如 Windows 中的问题代码和 M365 的性能关键层。对 C# 开发者而言,这意味着 Rust 的威胁有限,更多是补齐 .NET 生态底层安全短板的机遇。

C# 与 Rust 的生态位分离:业务复杂度 vs 资源安全边界

C# 的主场是业务复杂度,凭借 LINQ、async/await、反射、Roslyn 源生成器、EF Core 等,擅长让领域模型低成本持续演化。Rust 的主场是资源与安全边界,无 GC、确定性析构、编译期内存安全,适合解析器、编解码、加解密、驱动、协议栈等“错一个字节就是 CVE”的层。两者互补,而非竞争。

替换 unsafe 与 C++/CLI:Rust 原生模块的实践路径

文章建议将 .NET 项目中为性能或调原生库而写的 unsafe 块、C++/CLI 桥接层替换为 Rust。Rust 编译为原生库,C# 通过 P/Invoke 或 LibraryImport 源生成器调用,边界清晰,unsafe 范围被收敛进 Rust 编译器的保证之内。这为 C# 架构师提供了明确的改造方向。

FFI 契约与 NativeAOT 的权衡:显式边界比语言选择更重要

跨语言互操作需显式定义映射契约(句柄、缓冲区、错误码协议),不能让对象“裸穿”。NativeAOT 虽能让 C# 产出原生二进制,但牺牲反射动态性,而反射是元数据驱动架构的根基。更现实的组合是 C# 在上做编排,Rust 在下做原生模块,中间是契约化边界。对架构师而言,定义干净 FFI 契约比纠结是否学 Rust 更有价值。

Q&A

微软将 Rust 列为 Tier-1 语言,是否意味着 C# 会被取代?

不会。微软引入 Rust 的首要目标是替换有漏洞的 C/C++ 存量代码,而不是取代 C#。C# 和 Rust 在生态位上互补,C# 负责业务复杂度,Rust 负责资源与安全边界。

C# 和 Rust 在微软技术栈中各自擅长什么?

C# 擅长业务复杂度,如 LINQ、async/await、反射、Roslyn 源生成器、EF Core、ASP.NET Core 的 DI 与中间件,适合领域模型演化、DDD 聚合投影、元数据驱动运行时构图和复杂编排。Rust 擅长资源与安全边界,如无 GC、确定性析构、编译期内存安全,适合解析器、编解码、加解密、驱动、协议栈、热路径计算等对内存安全要求极高的层。

在 .NET 项目中,哪些部分最适合用 Rust 替换?

那些为了性能或调原生库而写的 unsafe 块、C++/CLI 桥接层,是最适合替换成 Rust 的部分。Rust 编译为原生库,C# 通过 P/Invoke 或 LibraryImport 源生成器调用,边界清晰,unsafe 的范围被收敛进 Rust 编译器的保证之内。

C# 与 Rust 互操作时需要注意哪些关键问题?

两条铁律:一是 panic 边界两边语义不同构,必须显式定义映射契约(句柄、缓冲区、错误码协议),不能让对象“裸穿”;二是跨语义系统的映射需要显式契约,而不是默认约定。

NativeAOT 会让 C# 与 Rust 竞争吗?

NativeAOT 让 C# 也能产出无运行时依赖的原生二进制,看似与 Rust 竞争,但代价是牺牲反射相关的动态性,而反射是元数据驱动架构(序列化框架、ORM、依赖注入、运行时类型构图)的根基。更现实的组合是 C# 在上做编排,Rust 在下做原生模块。

对于 C# 架构师,学习 Rust 和定义 FFI 契约哪个更重要?

学会在边界上定义干净的 FFI 契约,远比纠结“要不要学 Rust”更有价值。未来的高性能 .NET 系统,大概率是 C# 在上、Rust 在下,中间是一条显式的、契约化的边界。

🏷️

标签

➡️

继续阅读