这是因为init
个访问器被编译成一个带有modreq
声明的setter.Int属性P
的IL代码可能如下所示(请参见第SharpLab部分):
.method public hidebysig specialname
instance void modreq([System.Runtime]System.Runtime.CompilerServices.IsExternalInit) set_P (
int32 'value'
) cil managed
{
...
}
请注意 token modreq([System.Runtime]System.Runtime.CompilerServices.IsExternalInit)
.
普通的setter不会生成这个modreq
.
在调用方,当且仅当该方法上存在modreq
时,Call指令必须提供modreq
声明作为要调用的事物的签名的一部分.因此,对init
访问器的调用将如下所示:
callvirt instance void modreq([System.Runtime]System.Runtime.CompilerServices.IsExternalInit) SomeClass::set_P(int32)
而且不仅仅是
callvirt instance void SomeClass::set_P(int32)
如果更改为setter,则必须更改对init
访问器的所有调用以删除modreq
,否则它将无法正确解析该方法.因此,这是一个突破性的变化.
至于为什么使用modreq
而不是常规属性来标记特性,请参见规范草案中的this section.总而言之,这是二进制兼容性和"编译器不知道init
个访问器会做什么"之间的权衡.最后,他们决定牺牲二进制兼容性,以便不了解init
doesn't的编译器允许代码设置该属性.