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