C# 为什么C“编译器授权”;抛出“ex”;在catch中,是否存在“以下情况”;抛出“ex”;有用吗?

C# 为什么C“编译器授权”;抛出“ex”;在catch中,是否存在“以下情况”;抛出“ex”;有用吗?,c#,exception,exception-handling,C#,Exception,Exception Handling,在C#中,年轻的开发人员经常使用“throw ex”而不是“throw”来向父方法抛出异常 例如: try { // do stuff that can fail } catch (Exception ex) { // do stuff throw ex; } “throw ex”是一种不好的做法,因为堆栈跟踪在失败的方法下面被截断。因此,调试代码更加困难。因此,代码必须是: try { // do stuff that can fail } catch (Ex

在C#中,年轻的开发人员经常使用“throw ex”而不是“throw”来向父方法抛出异常

例如:

try
{
    // do stuff that can fail
}
catch (Exception ex)
{
    // do stuff
    throw ex;
}
“throw ex”是一种不好的做法,因为堆栈跟踪在失败的方法下面被截断。因此,调试代码更加困难。因此,代码必须是:

try
{
    // do stuff that can fail
}
catch (Exception ex)
{
    // do stuff
    throw;
}
我的问题是编译器为什么要授权它(或者不显示警告消息?)是否存在“throw ex”有用的情况?

throw new Exception()
抛出ex两者都将使用相同的语言规则来允许抛出异常对象(无论是新的还是现有的)。当您想添加一些额外的信息时,这个选项会很有帮助

请参阅:如何:

可以使用throw语句显式抛出异常。你 还可以使用throw语句再次抛出捕获的异常。 向重新抛出的异常添加信息是一种很好的编码实践,以便在调试时提供更多信息。

因为,
抛出新异常()
抛出异常
需要相同的语言规则,区分这两种规则并不是编译器的工作

简单地抛出现有异常而不修改异常对象将使用相同的语言构造

正如@D Stanley在他的文章中指出的,截断堆栈跟踪可能是理想的行为

至于您关于编译器不警告的问题,编译器的工作不是警告错误实践,而是提供代码分析工具。例如,托管代码分析工具将针对throw ex发出警告

有没有一种情况下“抛出ex”是有用的

当然-有时您希望截断堆栈跟踪-以避免暴露实现细节等。有时您可能希望抛出新异常,这意味着编译器必须区分只是重新抛出捕获的异常和抛出新异常


那么,为什么您希望编译器阻止您做一些1)不违法,2)可能有用的事情呢

虽然编译器当然可以防止一些明显的编程错误,但他们不可能在不触发一些不可避免的误报的情况下,留意这样的最佳实践

程序员可以选择在异常处理程序中更改异常的内容,或者抛出一个全新的异常。在这两种情况下,警告从异常处理程序引发异常的消息都是恼人和无用的

当您从递归函数中抛出异常时,会发生一种情况,即更改异常的内部状态是有意义的。考虑递归下降分析器,报告从递归链向下的几个层的错误。每一级调用都可能为异常添加更多有用的信息。但是,在这种情况下,将每个后续层的异常包装到一个新的异常中是不实际的,因为最终会得到一个表示平面列表的递归数据结构。对于这种情况,一个可行的解决方案是创建一个自定义异常,每个捕获者可以在重新抛出它之前添加更多细节。由于函数(或者更准确地说,一组函数)是递归的,因此在代码中引发原始异常的位置不如导致异常的上下文的完整性重要


这并不意味着发现这样的情况是完全无用的:代码校对工具,如ReSharper,当然可以帮助程序员注意这样的问题。然而,编译器对于一个最佳实践监视器来说是一个糟糕的选择,因为大多数情况下编译器应该做它所告诉的。

我想我认为<代码> catch >代码>当你实际上只想在栈中传播某个东西时的罪魁祸首。难道不应该为了最终的
而完全避免
捕获

bool bSucceeded = false;
try
{
    // do stuff that can fail
    bSucceeded = true;
}
finally
{
    if( !bSucceeded ) 
        // do stuff you need to do only on error.  (rare, for me)

    // cleanup stuff (you're nearly always doing this anyways right?)
}
我已经写了很多
b继承的
,我想我从来没有在
catch
中写过
throw
而不包含新的异常()。(至少从99年左右我第一次学习Java开始。)


我猜有很多可能的方法来解决这个问题,这就是为什么他们让你做你想做的事情,而不是试图锁定它

编译器不是用来捕捉糟糕的编程实践的。当
throw ex
正是你想要做的事情时,你会怎么办?@jgauffin我认为D Stanley的回答正好为我做到了这一点……更准确地说,你的问题应该是“为什么C#编译器不阻止你使用特定的构造?”(例如,
throw ex
)在某些位置”-显而易见的答案是,他们为什么要花时间专门更改编译器以防止这种情况?抓住真正困难的空
catch(Exception){
?这些可能是真正的调试难题。但是,如果我们不能忽略
ThreadAbortException
,这将是在一个新异常中“包装”异常,而不仅仅是重新抛出相同的异常(可能是不变的),那会有多烦人异常对象。@ebyrob、
throw new exception
throw ex
需要相同的语言结构,我在回答中解释得不够清楚。谢谢。为什么对编译器能做什么/不能做什么有这么多猜测?如果它能区分
If(x=1)
If(x==1)
作为一个警告,你不认为它可以处理这个案件……如果值得追查吗?@ebyrob,这不是猜测,
如果(x=1)
如果(x=1)
是另一回事。
抛出
另一方面可以