readonly是否有任何运行时开销?

Jul*_*anR 18 c# performance readonly immutability

出于某种原因,我一直认为readonly字段有与它们相关的开销,我认为这是CLR跟踪readonly字段是否已经初始化.这里的开销是一些额外的内存使用量来跟踪状态并在分配值时进行检查.

也许我假设这是因为我不知道一个readonly字段只能在构造函数内或字段声明本身内初始化,并且没有运行时检查,你将无法保证它不被多次分配给各种方法.但是现在我知道了,它可以很容易地被C#编译器静态检查,对吧?那是这样的吗?

另一个原因是,我已经读过使用readonly具有"轻微"性能影响,但他们从未涉及此声明,我无法找到有关此主题的信息,因此我的问题.我不知道除了运行时检查之外还有什么其他性能影响.

第三个原因是我看到它readonly在编译的IL 中被保留为initonly,所以这个信息在IL中的原因readonly是什么,如果只是C#编译器的保证,该字段永远不会分配给构造函数或声明?

另一方面,我发现你可以在readonly int没有CLR抛出异常的情况下设置通过反射的值,如果readonly是运行时检查则不可能.

所以我的猜测是:'readonlyness'只是一个编译时功能,任何人都可以确认/否认这个吗?如果是,那么这些信息被包含在IL中的原因是什么?

Szy*_*zga 16

您必须从与访问修饰符相同的角度来看待它.访问修饰符存在于IL中,但它们是否真的是运行时检查?(1)我不能在编译时直接分配私有字段,(2)我可以使用反射来分配它们.到目前为止似乎没有运行时检查,就像readonly.

但是让我们检查一下访问修饰符.请执行下列操作:

  1. 使用公共类C创建程序集A.dll
  2. 创建一个引用A.dll的程序集B.exe.B.exe使用C类.
  3. 构建两个程序集.运行B.exe工作正常.
  4. 重建A.dll但将C类设置为内部.替换B.exe目录中的A.dll.

现在,运行B.exe会抛出运行时异常.

IL中也存在访问修饰符,对吧?那他们的目的是什么?目的是引用.Net程序集的其他程序集需要知道允许访问它们的内容以及它们不允许访问的内容,包括编译时和运行时.

Readon似乎在IL中有类似的目的.它告诉其他程序集是否可以写入特定类型的字段.但是,readonly 似乎没有访问修饰符在上面的示例中显示的相同运行时检查.看起来readonly是一个编译时检查,并不会在运行时发生.看一下这里的性能示例:只读性能与常量.

同样,这并不意味着IL无用.IL确保首先发生编译时错误.请记住,在构建时,不要构建代码,而是构建程序.


Ree*_*sey 6

如果您使用的是标准的实例变量,则readonly的执行几乎与普通变量完全相同.添加的IL变为编译时检查,但在运行时几乎被忽略.

如果您使用静态只读成员,事情会有所不同......

由于静态只读成员是在静态构造函数中设置的,因此JIT"知道"存在一个值.没有额外的内存 - readonly只是阻止其他方法设置它,但这是一个编译时间检查.

JIT知道这个成员永远不会改变,它在运行时会被"硬编码",所以最后的效果就像拥有一个const值一样.不同之处在于它在JIT时间本身需要更长的时间,因为JIT编译器需要做额外的工作来将readonly的值硬连接到位.(但这会非常快.)

Marcus Hegee的专家C++/CLI对此有一个相当不错的解释.