Advanced C# Tips: Don't Use unsafe for Minor Gains

Advanced C# Tips: Don't Use unsafe for Minor Gains

高级 C# 技巧:不要为了微小的收益而使用 unsafe

The title could have also been "Don't use unsafe code at all!" You will come to the same conclusion after reading this post, but still I gave a room for its usage. In C#, the usage of unsafe code is a topic of debate. On one side, it offers the potential for performance gains in specific scenarios. Yet the risks and complexities it introduces often outweigh its benefits.

这篇文章的标题本也可以是"根本不要使用 unsafe 代码!"读完这篇文章后你会得出相同的结论,但我仍然为它的使用留下了一些空间。在 C# 中,unsafe 代码的使用是一个有争议的话题。一方面,它在特定场景中提供了性能提升的潜力。然而,它带来的风险和复杂性往往超过了它的好处。

What is unsafe

什么是 unsafe

Unsafe code in C# refers to a block of code that uses pointers and allows direct memory manipulation, bypassing the .NET runtime's type safety and security checks. This capability is powerful, but it comes with considerable risks. It allows developers to step outside the managed environment of the .NET runtime. It offers control over memory operations. However, it comes with a cost. My opinion about this debate would be this: if you are working on an application which can be solved in C# or its closest equivalent Java, you shouldn't need memory level manipulations. If you need re-assess your requirements and design. If you really believe that you need unsafe, you may consider using a different language (like C, C++, D, Rust etc.) which naturally supports memory level manipulations.

C# 中的 unsafe 代码是指使用指针并允许直接内存操作的代码块,它绕过了 .NET 运行时的类型安全和安全检查。这种能力很强大,但也带来了相当大的风险。它允许开发者走出 .NET 运行时的托管环境。它提供了对内存操作的控制。然而,这是有代价的。我对这个争论的看法是:如果你正在开发一个可以用 C# 或与其最接近的等价语言 Java 来解决的应用程序,你就不应该需要内存级别的操作。如果你需要,请重新评估你的需求和设计。如果你真的认为你需要 unsafe,你可以考虑使用另一种语言(如 C、C++、DRust 等),这些语言天然支持内存级别的操作。

In C#, unsafe code specifically refers to sections of code marked with the unsafe keyword. This keyword allows the use of pointers. For readers who are not familiar with pointers, a pointer is a variable that holds the memory address of another variable. So, the pointer allows direct access to the memory and also allows ability to manipulate the data in memory.

在 C# 中,unsafe 代码特指用 unsafe 关键字标记的代码段。这个关键字允许使用指针。对于不熟悉指针的读者来说,指针是一个保存另一个变量的内存地址的变量。因此,指针允许直接访问内存,也允许操作内存中的数据。

In system-level languages like C and C++, pointers are first class citizens of the language. They are natural parts in the toolbox and are commonly used for various types of problems. However, in languages like C# and Java, direct hardware access is abstracted with another layer on top of the operating system. For Java it is called Java Virtual Machine (JVM) for example, and for C# it is Common Language Runtime (CLR). These runtimes undertake the memory management and doesn't let developer to do this since manipulating them may cause significant problems. Before going into the details of why we should avoid, I want to show usage of unsafe in C# and talk about use cases that unsafe is used.

在 C 和 C++ 这样的系统级语言中,指针是语言的一等公民。它们是工具箱中的自然组成部分,通常用于解决各种类型的问题。然而,在 C# 和 Java 这样的语言中,直接硬件访问被操作系统之上的另一层抽象了。例如,Java 称之为 Java 虚拟机(JVM),C# 称之为公共语言运行时(CLR)。这些运行时承担了内存管理的工作,并且不让开发者来做这件事,因为操作它们可能导致重大问题。在深入探讨我们为什么要避免使用之前,我想先展示一下 C# 中 unsafe 的用法,并谈谈使用 unsafe 的用例。

In this example, we use pointer manipulation to access the memory address of a variable. This approach bypasses the type safety and memory safety provided by the .NET runtime.

在这个示例中,我们使用指针操作来访问变量的内存地址。这种方法绕过了 .NET 运行时提供的类型安全和内存安全。

unsafe {
    int var = 5;
    int* ptr = &var;
    Console.WriteLine("Value of var: {0}", var);
    Console.WriteLine("Address of var: {0}", (long)ptr);
}

Some commonly used cases where unsafe code is considered are listed below. Generally, they are performance critical problems.

下面列出了一些被认为可能使用 unsafe 代码的常见情况。通常,它们是性能关键型问题。

  • High-Performance Computing: Applications that require intense mathematical calculations, like scientific simulations, might benefit from unsafe code.
  • 高性能计算:需要大量数学计算的应用,如科学仿真,可能会受益于 unsafe 代码。
  • Interoperability: When interfacing with low-level system APIs or hardware, unsafe code might be necessary for direct memory access.
  • 互操作性:在与底层系统 API 或硬件进行对接时,直接内存访问可能需要 unsafe 代码。
  • Image Processing: Operations on large image data sets where performance is crucial might warrant the use of unsafe code.
  • 图像处理:在性能至关重要的大型图像数据集上的操作可能有理由使用 unsafe 代码。

Why we should avoid unsafe?

为什么我们应该避免使用 unsafe?

Why using unsafe code is being described such a sin? By using unsafe code, developers bypass critical safety features of the .NET runtime. The most common concerns are as follows:

为什么使用 unsafe 代码被描述得如此罪过?通过使用 unsafe 代码,开发者绕过了 .NET 运行时的关键安全特性。最常见的顾虑如下:

1. Type Safety: In safe code, the .NET CLR enforces a strict type checking. In other words, the type of every object is known and checked at runtime. It prevents operations that are not safe for that particular type. In unsafe code however, this well-organized type checking is bypassed. Developers can perform operations that the runtime would normally prohibit due to type incompatibility. It has the risk of errors such as type mismatches which can lead to unpredictable behaviour or application crashes.

1. 类型安全: 在安全代码中,.NET CLR 强制进行严格的类型检查。换句话说,每个对象的类型在运行时都是已知的并被检查。它防止了对该特定类型不安全的操作。然而,在 unsafe 代码中,这种组织良好的类型检查被绕过了。开发者可以执行运行时通常会因类型不兼容而禁止的操作。这存在类型不匹配等错误的风险,可能导致不可预测的行为或应用程序崩溃。

2. Memory Safety: The .NET CLR manages memory automatically through garbage collection. It allocates and deallocates memory, ensuring that objects no longer in use are properly cleaned up. This greatly reduces the likelihood of memory leaks and memory corruption. In unsafe code, developers have direct control over memory allocation and deallocation. This manual management can lead to issues like memory leaks and memory corruption, both of which can cause application instability and data loss.

2. 内存安全: .NET CLR 通过垃圾回收自动管理内存。它分配和释放内存,确保不再使用的对象被妥善清理。这大大降低了内存泄漏和内存损坏的可能性。在 unsafe 代码中,开发者可以直接控制内存的分配和释放。这种手动管理可能导致内存泄漏和内存损坏等问题,两者都可导致应用程序不稳定和数据丢失。

3. Security: The managed environment of the .NET, CLR provides a layer of protection against various security vulnerabilities. For instance, it prevents operations that could write data to arbitrary memory locations, a common exploit in security attacks. However, the direct memory access provided by unsafe code can expose applications to security risks, such as buffer overflow attacks. In these attacks, an attacker could exploit the ability to write beyond the bounds of allocated memory to inject malicious code or access sensitive data.

3. 安全性: .NET 的托管环境 CLR 提供了针对各种安全漏洞的一层保护。例如,它防止了可能将数据写入任意内存位置的操作,这是安全攻击中常见的利用方式。然而,unsafe 代码提供的直接内存访问可能使应用程序暴露于安全风险之下,例如缓冲区溢出攻击。在这些攻击中,攻击者可以利用超出已分配内存边界写入的能力来注入恶意代码或访问敏感数据。

Of course the reasons for not using unsafe code are not limited to the ones above.

当然,不使用 unsafe 代码的原因不限于以上几点。

To sum up, the risks associated with manual memory management, type safety violations, and security vulnerabilities need to be thought twice before using. They are far outweigh for the minor performance benefits. Developers should leverage the advanced features and optimizations provided by the .NET runtime. Even though I don't advice, developers should only use unsafe code when it is unavoidable necessary. If developers prefer doing so, they ensure that the applications they build are secure, maintainable, and as portable as possible.

总而言之,与手动内存管理、类型安全违规和安全漏洞相关的风险在使用前需要再三思考。它们远远超过了微小的性能收益。开发者应该利用 .NET 运行时提供的高级特性和优化。虽然我不建议,但开发者应仅在不可避免且必要时才使用 unsafe 代码。如果开发者执意这样做,他们应确保所构建的应用程序是安全的、可维护的,并且尽可能具有可移植性。

See Microsoft's reference for unsafe here.

请参阅微软关于 unsafe 的参考文档此处


Suleyman Cabir Ataman, PhD


This entry is part 11 of 17 in the series Advanced C# Tips.
本文是 Advanced C# Tips(高级 C# 技巧) 系列 17 篇中的第 11 篇。

posted @ 2026-06-03 11:45  talentzemin  阅读(4)  评论(0)    收藏  举报