为什么连续抛出2个异常不会产生无法访问的代码警告?

时间:2011-06-16 12:11:22

标签: c# compiler-warnings throw

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

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

正如我所看到的,编译器应通知您无法达到第二次抛出异常。

3 个答案:

答案 0 :(得分:38)

这显然是一个编译器错误,它是在C#3.0中引入的 - 就在我大量重构可达性检查器的时候。这可能是我的坏事,抱歉。

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

该错误只不过是警告生成器中的缺失案例。我们在那里有一些棘手的代码,可以确保当您使一些大部分代码无法访问时,我们不会报告大量警告。编译器具有专门报告无条件getos警告的代码(“goto”,“break”,“continue”),条件gotos(“if”,“while”等等),try-catch-finally(包括等效表单) to try-catch-finally,如lock和using),blocks,returns(yield return和regular return),本地声明,带标签的语句,开关和表达式语句。

您是否在该列表中看到“抛出语句”?我也不。那是因为我们忘了它。

对此造成的不便表示歉意。我将向QA发送一份说明,我们将为此修复该语言的未来版本。

感谢您引起我的注意。

答案 1 :(得分:7)

它可能会给编译器警告/错误,但遗憾的是它没有。但是如果你看一下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。

答案 2 :(得分:3)

这个错误(正如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编译器,此行为似乎没有改变。