好的,请考虑以下代码:
const bool trueOrFalse = false;
const object constObject = null;
void Foo()
{
if (trueOrFalse)
{
int hash = constObject.GetHashCode();
}
if (constObject != null)
{
int hash = constObject.GetHashCode();
}
}
trueOrFalse
是一个编译时间常数,因此,编译器正确警告int hash = o.GetHashCode();
无法访问。另外,
constObject
是一个编译时间常数,因此编译器会再次正确警告int hash = o.GetHashCode();
无法访问,因为o != null
将永远不会是true
。那么,为什么编译器不知道这一点:
if (true)
{
int hash = constObject.GetHashCode();
}
是否100%确定是运行时异常并因此发出了编译时错误?我知道这可能是一个愚蠢的极端情况,但是编译器似乎很聪明地就编译时间常数值类型进行了推理,因此,我期望它也可以找出带有引用类型的这种极端情况。
最佳答案
更新:这个问题是t he subject of my blog on July 17th 2012。谢谢伟大的问题!
为何编译器应生成保证会引发编译时错误的代码?那会不会:
int M()
{
throw new NotImplementedException();
}
进入编译时错误?但这恰恰与您想要的相反。您希望这是一个运行时错误,以便编译不完整的代码。
现在,您可能会说,好吧,取消引用null总是总是不希望的,而显然“undefined”异常是令人希望的。那么,编译器是否可以仅检测这种特定情况,即肯定会发生null ref异常,并给出错误?
当然可以。我们只需要花费预算就可以实现一个数据流分析器,该分析器可以跟踪已知的给定表达式始终为null的时间,然后使其成为编译时错误(或警告)以取消对该表达式的引用。
然后要回答的问题是:
第一个问题的答案是“相当多”-代码流分析器的设计和构建成本很高。第二个问题的答案是“不是很多”-您可以证明将要取消引用null的情况的数量非常少。在过去的十二年中,第三个问题的答案始终是"is"。
因此,没有这样的功能。
现在,您可能会说,好吧,C#确实具有检测表达式何时总是/永不为null的有限能力。可为空的算术分析器使用此分析来生成更多最佳的可为空的算术代码(*),并且很明显,流量分析器使用它来确定可达性。那么,为什么不仅仅使用已经存在的可空性和流量分析器来检测何时始终取消引用空常量呢?
当然,实现起来很便宜。但是,现在相应的用户 yield 很小。您在真实代码中将常量初始化为null多少次,然后取消对其的引用?似乎不太可能有人真正做到这一点。
此外:是的,在编译时而不是在运行时检测错误总是更好,因为它更便宜。但是这里的错误-保证取消引用null-将会在第一次测试代码时被捕获,并随后得到修复。
因此,基本上,这里的功能要求是在编译时检测到非常不可能且显而易见的错误情况,该错误情况总是在首次运行代码时立即被发现并修复。因此,它不是将预算用于执行预算的很好的候选人;我们有很多更高的优先级。
(*)参见有关Roslyn编译器如何执行此操作的长篇文章,该文章始于http://ericlippert.com/2012/12/20/nullable-micro-optimizations-part-one/
关于c# - 编译时间常数和引用类型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8975666/