8

我了解指针以及很少需要在 C# 代码中使用它们。我的问题是:必须在代码块中明确声明“不安全”的原因是什么。此外,为什么必须更改编译器选项以允许“不安全”代码?

底线: CLR(或语言规范)中的什么使得我们不能只在需要时使用指针(很像 C 和 C++)而不必键入“不安全”并更改编译器选项?

澄清一下:我知道什么是“不安全”和“安全”代码。这只是一个问题,为什么我们必须做所有额外的工作(好吧,不是那么多额外的工作)才能使用这些功能。

4

9 回答 9

9

这里有一篇对 C# Creator Anders Hejlsberg 的采访,涉及到这个主题。基本上,正如@Marc Gravell 所说:类型安全第一,显式声明不安全。

所以回答你的问题:CLR 中没有任何东西可以阻止它;这是一种语言习语,旨在让您在处理类型时戴上安全手套。如果你想脱掉手套,这是你的选择,但你必须做出主动的选择来脱掉手套。

编辑:

澄清一下:我知道什么是“不安全”和“安全”代码。这只是一个问题,为什么我们必须做所有额外的工作(好吧,不是那么多额外的工作)才能使用这些功能。

正如我在采访中提到的那样,这是一个明确的设计决定。C# 本质上是 Java 的演变,而在 Java 中,您根本没有指针。但是设计者希望允许指针;然而,由于 C# 通常会引入 Java 开发人员,他们认为最好是默认行为类似于 Java,即没有指针,同时仍允许通过显式声明使用指针。

所以“额外的工作”是故意强迫你在做之前考虑你在做什么。通过明确,它迫使您至少考虑:“我为什么要这样做?当引用类型就足够了时,我真的需要一个指针吗?”

于 2009-03-03T16:46:52.527 回答
7

这主要是关于可验证的。通过声明unsafe,手套已经关闭 - 系统无法再保证您的代码不会乱跑。在大多数情况下,非常希望留在安全区。

这在部分信任(插件等)中变得更加明显,但在常规代码中仍然很有价值。

于 2009-03-03T16:40:24.133 回答
3

实际上,CLR 对 /unsafe 开关或关键字没有任何要求。实际上,C++/CLI(运行在CLR下的C++语言)没有这样的/unsafe开关,在CLR上可以自由使用指针。

因此,我将您的问题改写为“为什么 C# 需要在使用指针之前使用 /unsafe?” 该问题的答案与此处给出的其他答案中所述:帮助用户做出有意识的决定,失去在 CLR 上以低于完全信任模式运行的能力。C++ 实际上总是要求 CLR 上的完全信任,而 C#可以在您调用需要完全信任的代码时或在您使用指针时。

于 2009-03-03T16:57:32.610 回答
2

当您使用不安全的块时,它具有使代码无法验证的效果。这需要某些权限才能执行,并且您可能不想在输出中允许它(特别是如果您处于共享源环境中),因此编译器中有一个开关来禁止它。

于 2009-03-03T16:41:33.117 回答
2

从相反的角度考虑:因为它没有被标记为不安全,你可以推断大多数代码默认是“安全的”。那么什么是“安全”呢?对于 .Net 代码,这包括(但可能不限于):

  • 垃圾收集器可以照常工作。
  • 对特定类型的引用引用该类型(或 null)的对象。
  • 保证代码符合 .Net 信任/安全要求。
  • 该代码在数学上被证明不会直接接触它自己的 AppDomain 之外的内存。这可能看起来微不足道,但想象一下,如果您在同一个应用程序中有多个 AppDomain。程序员可以自信地将它们视为逻辑上分离的。

任何时候你使用指针,你都有机会打破这些保证。因此,将代码标记为不安全会放弃这些保护。

于 2009-03-03T16:47:13.490 回答
2

简而言之,.NET 希望您陈述您的意图。

当然,编译器可以推断出需要“不安全”标志。但设计师希望这是一个深思熟虑的决定。

对我来说,这类似于 C# 中的一些语法要求:

  • 无开关盒无中断
  • 没有访问级别的“节”(例如 C++ 中的“public:”标记)
  • 没有使用“var”的类字段

模式是你不应该移动或改变一件事而无意中影响另一件事。在合理的范围内,他们想让你不要“在脚上开枪”。

这里有很多很棒的、内容丰富的答案——也许这更适合你的问题。

于 2009-03-03T18:05:31.807 回答
1

因此,如果没有提升的权限等,哪些代码不会在 Web 服务中运行是显而易见的。

于 2009-03-03T16:40:35.160 回答
1

培养良好的习惯和安全感。每当您在程序集中使用不安全块时,都会要求堆栈提供 NativeCode 权限。这当然可以隐式完成,但我们不能也完全删除 private 关键字吗?我认为强制开发人员在使用之前明确要求不安全的代码是件好事。

于 2009-03-03T16:41:05.473 回答
1

安全代码和不安全代码之间最显着的区别是 .net 的垃圾收集器无法访问不安全代码。自动 GC 是 .net 语言的重要组成部分,当你超越它的界限时,你会改变很多关于你的代码的假设。

指针尤其允许在没有 GC 引用的情况下在堆上创建对象。这导致另一个极好的理由要求将代码标记为“不安全”。当您意识到自己有内存泄漏时,它可以很容易地缩小内存泄漏的来源。

于 2009-03-03T16:47:57.763 回答