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的回答中所解释的那样。