C#:明确声明“不安全”/编译器选项的好处

时间:2009-03-03 16:37:42

标签: c# pointers unsafe compiler-options

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

底线: CLR(或语言规范)中的内容使得我们不能随时使用指针(很像C和C ++)而不必输入“unsafe”和更改编译器选项?

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

9 个答案:

答案 0 :(得分:9)

接受了C#Creator Anders Hejlsberg的采访,涉及主题here。基本上,正是@Marc Gravell所说的:首先是类型安全,通过明确声明不安全。

所以回答你的问题:CLR中没有任何东西阻止它;它是一种语言习语,旨在让您在处理类型时使用安全手套。如果你想脱下手套,这是你的选择,但你必须做出积极的选择才能脱下手套。

修改

  

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

正如我所接受的采访中提到的,这是一个明确的设计决定。 C#本质上是Java的演变,在Java中,你根本就没有指针。但设计师想要指点;但是因为C#通常会引入Java开发人员,他们认为如果默认行为与Java类似,即没有指针,同时仍允许通过显式声明使用指针,那将是最好的。

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

答案 1 :(得分:7)

主要是关于可验证的。通过陈述unsafe,手套关闭 - 系统无法保证您的代码不会无法正常运行。在大多数情况下,非常希望留在安全区。

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

答案 2 :(得分:3)

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

所以我将你的问题改为“为什么C#在使用指针之前需要使用/ unsafe?”这个问题的答案如此处给出的其他答案中所述:帮助用户有意识地决定失去在CLR上以低于完全信任模式运行的能力。 C ++几乎总是需要CLR上的完全信任,并且只要您调用需要完全信任的代码,或者无论何时使用指针,C#都可以

答案 3 :(得分:2)

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

答案 4 :(得分:2)

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

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

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

答案 5 :(得分:2)

简而言之,.NET希望您说明您的意图。

当然,编译器可以推断出对“不安全”标志的需求。但设计师希望这是一个慎重的决定。

对我而言,它类似于C#中的一些语法要求:

  • 没有休息的开关案例
  • 没有访问级别的“部分”(例如C ++中的“public:”标记)
  • 没有使用“var”的类字段

模式是你不应该移动或改变一件事而无意中影响另一件事。在合理的范围内,他们希望阻止你“自己在脚下射击。”

这里有很多很好的,信息丰富的答案 - 也许这更适合你的问题。

答案 6 :(得分:1)

因此,很明显,如果没有提升权限等,哪些代码将无法在Web服务中运行。

答案 7 :(得分:1)

养成良好的习惯&安全。每当在程序集中使用不安全的块时,都会从堆栈中请求NativeCode权限。这当然可以隐式完成,但我们不能完全删除private关键字吗?我认为强迫开发人员在使用之前专门要求不安全的代码是好的。

答案 8 :(得分:1)

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

指针特别允许在堆上创建没有GC引用的对象。这导致另一个很好的理由要求将代码标记为“不安全”。当您意识到有内存泄漏时,可以轻松缩小内存泄漏的范围。