为什么以下代码行不会产生编译器警告?
void Main()
{
throw new Exception();
throw new Exception();
}
如我所见,编译器应该通知您无法达到第二个抛出异常。
为什么以下代码行不会产生编译器警告?
void Main()
{
throw new Exception();
throw new Exception();
}
如我所见,编译器应该通知您无法达到第二个抛出异常。
这显然是一个编译器错误,它是在 C# 3.0 中引入的——就在我大量重构可达性检查器的时候。这可能是我的错,对不起。
该错误是完全良性的;基本上,我们只是在警告记者中忘记了一个案例。我们正确生成可达性信息;正如其他人所指出的,我们在 codegen 之前正确地修剪了无法访问的代码。
该错误只不过是警告生成器中的一个缺失案例。我们那里有一些棘手的代码,可确保当您使大部分代码无法访问时,我们不会报告无数警告。编译器具有专门报告无条件 goto(“goto”、“break”、“continue”)、条件 goto(“if”、“while”等)、try-catch-finally(包括等效形式)的代码try-catch-finally,如 lock 和 using)、块、返回(yield 返回和常规返回)、局部声明、标记语句、开关和表达式语句。
您在该列表上看到“抛出语句”吗?我也不。那是因为我们忘记了。
造成的不便,深表歉意。我将向 QA 发送一条说明,我们将在该语言的未来版本中对此进行修复。
感谢您引起我的注意。
它可能会给出编译器警告/错误,但遗憾的是它没有。但是,如果您查看 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
在第一个 Exception 对象之后,没有其他任何东西被转换为 IL。
这个错误(正如 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 编译器中似乎没有改变。