为什么在一行中抛出2个异常不会生成无法访问的代码警告

本文关键字:警告 代码 访问 异常 2个 一行 为什么 | 更新日期: 2023-09-27 17:59:13

为什么以下几行代码没有创建编译器警告?

void Main()
{
  throw new Exception();
  throw new Exception();
}

在我看来,编译器应该通知您无法到达第二个抛出异常。

为什么在一行中抛出2个异常不会生成无法访问的代码警告

这显然是一个编译器错误,它是在C#3.0中引入的——就在我大力重构可达性检查器的时候。这可能是我的错,对不起。

这个bug是完全良性的;基本上,我们只是忘记了警告记者的一个案例。我们正确地生成可达性信息;正如其他人所指出的,我们在codegen之前正确地修剪掉了无法访问的代码。

这个错误只不过是警告生成器中的一个缺失案例。我们有一些棘手的代码,可以确保当您无法访问某个大段代码时,我们不会报告无数警告。编译器有专门报告无条件goto("goto"、"break"、"continue")、有条件gotos("if"、"while"等)、try-catch finally(包括等价于try-catch的形式,如lock和using)、块、返回(yield return和正则返回)、局部声明、带标签的语句、开关和表达式语句警告的代码。

你在清单上看到"抛出声明"了吗?我也是。那是因为我们忘了。

对给您带来的不便深表歉意。我会给QA发一个通知,我们会在未来的语言版本中对此进行修复。

谢谢你引起我的注意。

它可能会发出编译器警告/错误,但遗憾的是,它没有。但若你们观察IL代码,只会发现第一个异常。您可以登录到connect.microsoft.com并将其作为您希望看到的内容。

如果你在下面输入代码

static void Main(string[] args)
        {
            Console.Write("Line 1");
           throw new Exception(); 
           throw new Exception();
           Console.Write("Line 4");
        }

你会得到这个

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       18 (0x12)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "Line 1"
  IL_0006:  call       void [mscorlib]System.Console::Write(string)
  IL_000b:  nop
  IL_000c:  newobj     instance void [mscorlib]System.Exception::.ctor()
  IL_0011:  throw
} // end of method Program::Main

在第一个Exception对象之后,没有任何其他对象转换为IL。

这个bug(Lippert在上面称之为)有一些奇怪的后果。当然,像这样的代码也不会在编译时发出警告:

static int Main()
{
  return 0;
  throw new Exception("Can you reach me?");
}

如果你有创意,你仍然可以让throw语句引发(不相关的)警告。在这个奇怪的例子中,代码只因为无法访问"绿色"而生成警告:

static int Main()
{
  return 0;
  throw new Exception(((Func<string>)(() => { if (2 == 2) { return "yellow"; } return "green"; }))());
}

(代码只是从lambda创建一个委托实例并调用该委托)。

但这个例子更简单,看起来更糟:

static int Main()
{
  int neverAssigned;
  return 0;
  throw new Exception(neverAssigned.ToString());
}

最后一个代码示例编译时也没有任何警告!"使用"neverAssigned没有问题,因为"用法"是不可访问的。但是,对于从未分配给(也从未"真正"读取)的局部变量,您也不会得到任何警告。再说一遍,没有任何警告,这似乎是非常错误的。

我想知道在Visual C#的未来版本中是否会改变这种行为?改变它会给人们以前没有的警告(在我看来,这是他们应得的)。

添加:此行为在Visual Studio 2015的基于Roslyn的C#6.0编译器中似乎没有变化。