【问题标题】:Why does the compiler think Environment.Exit can return?为什么编译器认为 Environment.Exit 可以返回?
【发布时间】:2017-09-01 01:29:23
【问题描述】:

示例代码:

switch(something)
{
    case 0:
        System.Environment.Exit(0);
    case 1:
        // blah ...
        break;
}

它不会编译,因为编译器认为执行可以从 Exit() 返回。编译器明显错了。

没有技巧。 System.Environment.Exit() 是真的。

System.Environment.Exit() 返回不仅完全不合逻辑,而且我追踪了代码,它最终调用了无法返回的ExitProcess(exitCode);

【问题讨论】:

  • 由于编译器无法查看方法的 IL 来了解运行时将执行什么(因为编译器绝对无法知道运行时将加载的确切程序集), 如何建议编译器知道给定的方法永远不会返回?
  • @AlexeiLevenkov:鉴于目前的情况,[System.Runtime.InteropServices.NoReturn] void Exit(int ExitCode);如果我重新写这个,会有一个类型(类似于 System.Void)意味着无法访问。
  • 属性不是方法签名的一部分 - 所以它不会工作,因为编译器不能保证在运行时加载的库实现该方法甚至会有属性(忽略编译器的事实并且 JIT 将不得不以某种方式强制执行该属性的行为)。确实,作为方法签名一部分的返回特殊类型会起作用,但是是否值得构建整个额外的基础设施来验证该方法不能为这种终止进程的方法的特殊情况返回?
  • @AlexeiLevenkov: function(out x) 撒谎。 out 实际上是[System.Runtime.InteropServices.Out]。它不是那么特殊的目的;任何保证抛出的方法都可以用这个标记;还要注意 C 和 C++ 有它。如果调用缺少它的运行时库,代码甚至不会加载,所以这是一个小问题。
  • 编译器只遵循specification:如果 expression_statement 可达,则 expression_statement 的端点是可达的。

标签: c# compiler-errors design-rationale


【解决方案1】:

就语言而言,它可以返回。是的,在现实生活中,进程将在有机会返回之前终止,但编译器不会根据方法签名知道这一点。

您需要在其中添加“中断”以使编译器满意。

【讨论】:

  • 很难准确解释这个答案有什么问题。这几乎就像是在回答什么而不是为什么。
  • 想象一下你有一个名为 'Foo' 的方法,它调用了System.Environment.Exit()。您是否希望switch 语句强制您在调用Foo() 之后调用break,或者您是否希望switch 语句通过检查其代码路径来理解Foo 的含义以知道它将终止进程并且永远无法返回?
  • 编译器不应该依赖于库调用的副作用。此特定调用不能保证有效,它可能会引发异常。
  • 曾经有一段时间我希望编译器会在这种情况下解决这个问题,但后来我了解到这是一个次优选择,它应该是声明的一部分。
  • @KeithNicholas:如果它抛出异常,它仍然不会通过这个案例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-12-19
  • 2010-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-03
相关资源
最近更新 更多