简体   繁体   English

为什么C#编译器在catch中授权“throw ex”,是否存在“throw ex”有用的情况?

[英]Why does the C# compiler authorize “throw ex” in catch, and is there a case where “throw ex” is useful?

In C#, younger developers use often "throw ex" instead of "throw" to throw exception to parent method. 在C#中,较年轻的开发人员经常使用“throw ex”而不是“throw”来向父方法抛出异常。

Example : 示例:

try
{
    // do stuff that can fail
}
catch (Exception ex)
{
    // do stuff
    throw ex;
}

"throw ex" is a bad practise because the stack trace is truncated below the method that failed. “throw ex”是一种不好的做法,因为堆栈跟踪被截断在失败的方法之下。 So it's more difficult to debug code. 因此调试代码更加困难。 So the code must be : 所以代码必须是:

try
{
    // do stuff that can fail
}
catch (Exception ex)
{
    // do stuff
    throw;
}

My question is why compilator authorize this (or doesn't display a warning message ?) Is there a case which "throw ex" is useful ? 我的问题是为什么编译器授权这个(或者不显示警告信息?)是否存在“抛出ex”有用的情况?

Is there a case which "throw ex" is useful ? 是否有“抛出前”有用的情况?

Sure - sometimes you want to truncate the stack trace - to avoid exposing implementation details, etc. Other times you may want to throw a new exception, which would mean the compiler would have to distinguish from just re-throwing the caught exception and throwing a new exception. 当然 - 有时你截断堆栈跟踪 - 以避免暴露实现细节等。其他时候你可能想要抛出一个新的异常,这意味着编译器必须区别于重新抛出捕获的异常并抛出一个新的例外。

So why would you want the compiler to prevent you form doing something that 1) is not illegal and 2) could be useful? 那么为什么你希望编译器阻止你做一些1)不违法的事情2)可能有用?

throw new Exception(); or throw ex; throw ex; both will use the same language rules to allow throwing an exception object, (whether new or existing) . 两者都将使用相同的语言规则来允许抛出异常对象(无论是新的还是现有的) When you want to add some extra information with the exception than that option is helpful. 当您想要添加一些额外信息时,该选项很有用。

See: How to: Explicitly Throw Exceptions - MSDN 请参阅:如何: 明确抛出异常 - MSDN

You can explicitly throw an exception using the throw statement. 您可以使用throw语句显式抛出异常。 You can also throw a caught exception again using the throw statement. 您还可以使用throw语句再次抛出捕获的异常。 It is good coding practice to add information to an exception that is re-thrown to provide more information when debugging. 将信息添加到重新抛出的异常以便在调试时提供更多信息是一种很好的编码实践。

Since both, throw new Exception() and throw ex; 既然两者都throw new Exception()throw ex; would require the same language rules, it is not really compiler's job to distinguish those two. 需要相同的语言规则,区分这两者并不是编译器的真正工作。

Simply throwing the existing exception without any modification to the exception object would be using the same language construct. 简单地抛出现有异常而不对异常对象进行任何修改将使用相同的语言构造。

Also as @D Stanley has pointed out in his answer , that truncating the stack trace could be the desired behaviour. 正如@D Stanley在他的回答中指出的那样,截断堆栈跟踪可能是期望的行为。

As far as your question about compiler not warning about it is concerned, It is not the job of compiler to warn about bad practices, there are code analysis tools. 关于编译器没有警告它的问题,编译器的工作不是警告不良做法,而是有代码分析工具。 For example Managed Code Analysis tool will raise the warning for throw ex; 例如,托管代码分析工具将引发throw ex;的警告throw ex; CA2200: Rethrow to preserve stack details CA2200:Rethrow保留堆栈详细信息

While compilers can certainly prevent some obvious programming errors, they cannot possibly watch out for best practices like that without triggering some inevitable false positives along the way. 虽然编译器当然可以防止一些明显的编程错误,但他们不可能在不引发一些不可避免的误报的情况下注意这样的最佳实践。

Programmers could choose to change the content of the exception inside the exception handler, or throw a brand-new exception instead. 程序员可以选择在异常处理程序中更改异常的内容,或者抛出一个全新的异常。 In both cases a message that warns about throwing an exception from an exception handler would be annoying and useless. 在这两种情况下,警告从异常处理程序抛出异常的消息将是烦人且无用的。

One case when it make sense to change the internal state of an exception happens when you throw an exception from a recursive function. 当从递归函数中抛出异常时,会发生更改异常内部状态的一种情况。 Consider a recursive descent parser reporting an error from several layers down the recursive chain. 考虑一个递归下降解析器,从递归链中的几个层报告错误。 Each level of invocation could potentially add more useful information to an exception. 每个级别的调用都可能为异常添加更多有用的信息。 However, wrapping exceptions of each subsequent layer into a new exception is not practical in this case, because you end up with a recursive data structure representing a flat list. 但是,在这种情况下,将每个后续层的异常包装到新的异常中是不切实际的,因为最终会得到表示平面列表的递归数据结构。 One viable solution for situations like this would be creating a custom exception to which each catcher can add more details before re-throwing it. 对于这种情况,一种可行的解决方案是创建一个自定义异常,每个捕获者可以在重新抛出之前添加更多细节。 Since the function (or more precisely, a group of functions) is recursive, the location in code from which the original exception has been thrown is of less importance than the completeness of the context that lead to the exception in the first place. 由于函数(或更确切地说,一组函数)是递归的,因此抛出原始异常的代码中的位置不如首先导致异常的上下文的完整性重要。

It does not mean that finding situations like that is entirely useless: code proofing tools, such as ReSharper, can certainly help programmers watch out for issues like this. 这并不意味着找到这样的情况完全没用:代码校对工具,如ReSharper,当然可以帮助程序员注意这样的问题。 The compiler, however, is a poor choice for a best practice watchdog, because for the most part the compiler should do what it is told. 但是,编译器对于最佳实践监视程序来说是一个糟糕的选择,因为在大多数情况下,编译器应该按照它所说的去做。

I guess I consider catch the culprit when you actually just want something to propagate up the stack. 我想我会考虑catch罪魁祸首,因为你实际上只是希望某些东西能够在堆栈中传播。 Shouldn't catch be avoided entirely in favor of finally ? 不应该catch避免完全赞成的finally

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?)
}

I've written many bSucceded 's, and don't think I have ever written throw inside catch without wrapping in a new Exception(). 我已经写了很多bSucceded的,不认为我曾经throw里面catch而不在一个新的异常包装()。 (At least since I was first learning Java in '99 or so.) (至少自从我在99年左右开始学习Java以来​​。)

I'm guessing the massive number of possible ways to deal with this is why they let you do what you want here instead of trying to lock it down. 我猜测大量可能的方法来解决这个问题,这就是为什么他们让你在这里做你想做的事情,而不是试图锁定它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM