Span 不需要局部变量赋值。 这是一个function吗?
我注意到即使没有初始化局部变量,下面的代码也会编译和执行。 这是Span的一个特色吗?
void Uninitialized() { Span s1; var l1 = s1.Length; Span s2; UninitializedOut(out s2); var l2 = s2.Length; } void UninitializedOut(out Span s) {}
这看起来像是由引用程序集引起的问题,因为Span
具有特定于框架的内部结构的方式。
这意味着在引用程序集中: 没有字段 (编辑:这不完全正确 – 请参阅脚注)。
如果分配了所有字段,则认为struct
被分配(出于“明确赋值”的目的),并且在这种情况下,编译器看到“已经分配了零字段的全部零:所有良好 – 分配了该变量”。 但编译器似乎并不知道实际的字段,所以它被误导为允许在技术上无效的东西。
你绝对不应该依赖这种表现! 虽然在大多数情况下.locals init
应该意味着你实际上并没有太可怕。 但是,目前正在进行一些工作以允许人们在某些情况下抑制 .locals init
– 我担心在这种情况下会发生什么 – 特别是因为Span
工作方式与ref T
非常相似 – 可能会非常如果该字段确实未初始化为零, 则 非常危险。
有趣的是,它可能已经修复 :请参阅sharplab上的这个示例 。 或者,也许sharplab使用的是具体的目标框架,而不是参考程序集。
编辑:非常奇怪,如果我将参考组件加载到ildasm
或reflection器,我可以看到:
.field private initonly object _dummy
这是参考组件中的欺骗字段, 旨在阻止这种情况发生,但……现在看起来它的工作效率不高!
更新:显然这里的差异是一个微妙但已知的编译器问题 ,仍然是出于兼容性原因; 结构的明确赋值考虑本地已知类型的私有字段,但不考虑外部程序集中类型的私有引用类型字段。
马克有一个很好的答案。 我想详细说明一下历史/背景。
首先,这绝对是一个编译器错误 。 根据明确赋值的规则,本地未明确分配,任何使用都应该是错误。 不幸的是,由于多种原因,这个bug很难解决:
- 这个bug很老,至少可以追溯到C#4.0。 这让客户在7年多的时间里无意中依赖它
- BCL中有许多具有这种基本结构的结构。 例如CancellationToken 。
这些合在一起意味着修复这可能会破坏大量现有代码。 尽管如此,当bug越来越年轻时,C#团队试图修复C#6.0中的错误。 但尝试使用此修复程序编译Visual Studio源代码表明,围绕客户依赖此错误的担忧是有根据的:有许多构建中断。 足以让我们相信它会对大量代码产生负面影响。 因此修复工作已经解决。
这里的第二个问题是所有编译器团队成员都不知道这个错误(至少在今天之前)。 距离修复工作已经3年了,从那时起就有了一些转变。 validation我们如何为Span
生成参考组件的团队成员不知道这个错误,并建议基于语言规范的当前设计。 我是那些开发者之一:(
仍在讨论这个问题,但我们很可能会更新Span
和其他类型的参考汇编策略,以避免这个编译器错误。
谢谢你报道这个。 抱歉造成的混乱:(
或多或少这是设计,因为它依赖于底层struct
本身是否包含任何字段。
此代码编译例如:
public struct MySpan { public int Length => 1; } static class Program { static void Main(string[] args) { MySpan s1; var l1 = s1.Length; } }
但是这段代码没有:
public struct MySpan { public int Length { get; } } static class Program { static void Main(string[] args) { MySpan s1; var l1 = s1.Length; } }
在这种情况下,结构似乎是默认的,这就是为什么它不会抱怨丢失的赋值。 它没有检测到任何字段是一个错误,正如Marc的回答中所解释的那样。