2011-06-16 21 views
32

为什么下面的代码行不会创建编译器警告?为什么在一行中抛出2个异常不会生成无法访问的代码警告?

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

在我看来,编译器应该告诉你的是,第二抛出异常无法达成。

+0

(我注意到,ReSharper的,标志着第二'throw'不可达) – AakashM 2011-06-16 12:56:50

+3

寻呼埃里克利珀的C#编译器6.0 .. – 2011-06-16 13:06:01

+0

@丹Eric Lippert在此之前表示[他不是kibo(在评论中)](http://stackoverflow.com/questions/2508945/can-anyone-explain-this-strange-behaviour) - 通过他与他联系博客,如果你想提醒他有兴趣的问题。 – AakashM 2011-06-16 13:51:00

回答

36

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

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

该错误只不过是警告生成器中的一个缺失情况。我们在那里有一些棘手的代码,可以确保当您将大部分代码无法访问时,我们不会报告数十万条警告。编译器具有代码,用于特别报告无条件gotos(“goto”,“break”,“continue”),条件gotos(“if”,“while”等),try-catch-finally try-catch-finally,像锁定和使用),块,返回(yield return和regular return),局部声明,标记语句,开关和表达式语句。

您是否在该列表上看到“throw statements”?我也不。那是因为我们忘了它。

不便之处,敬请原谅。我会向QA发送一条便条,我们将为此修复该语言的未来版本。

感谢您的关注。

+1

感谢Eric的解释。在我们的开发人员意外地重复了“抛出新的Exception()”代码行之后,我只是出于好奇而问,但项目仍然建立(Warnings as Errors on)。 – DaveShaw 2011-06-16 18:50:53

+0

@DaveShaw这个bug有一个奇怪的后果,我在新的“答案”中详细阐述了一下。 – 2012-08-15 19:35:11

7

它可以给编译器警告/错误,但可悲的是它没有。但是,如果你看IL代码,只有第一个例外被视为。您可以登录到connect.microsoft.com并将其作为您希望看到的内容提出。

如果你ILDASM下面

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 

第一异常对象没有别的转换为IL后。

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#中改变?改变它会给人们以前没有的警告(在我看来他们应该得到)。

增加:这种行为似乎是不变与Roslyn基础的Visual Studio的2015年

相关问题