除了构造异常之外,抛出异常会产生副作用吗?

时间:2015-06-15 14:09:54

标签: c# exception

我已经明白,抛出异常有副作用(比如收集堆栈信息),但我意识到它可能没有。以下两个GetException版本之间是否存在差异?

public Exception GetException() {
    try {
        throw new Exception("Bummer");
    }
    catch (Exception e) {
        return e;
    }
}

public Exception GetException() {
    return new Exception("Bummer");
}

2 个答案:

答案 0 :(得分:3)

当抛出异常时,堆栈跟踪被插入"进入异常(这是你可以通过StackTrace属性获得的)。所以是的,抛出异常对象会产生副作用。

重新抛出异常的问题(即使使用

throw;

是堆栈跟踪被破坏(甚至覆盖,如果你使用throw ex;))

请注意,throw; 优于throw ex;,因为第一个只会略微减少行数,而后者将完全重置堆栈跟踪。< / p>

有些人不信任......请查看https://dotnetfiddle.net/RXicN9并查看行号。他们是不同的。

一个更完整的示例,显示只有包含两个try... catch...的方法的行号被修改:https://dotnetfiddle.net/jJyYWB

有关说明,请参阅Incorrect stacktrace by rethrow。请注意,这是一种特殊情况,只有在同一方法中抛出异常两次才会发生。

答案 1 :(得分:2)

Yes, the two are different. The throw will modify the stack trace information in the Exception object - so your second example will still produce an exception, but without the stack trace information.

Exception-derived classes are classes as any other - all the "magic" happens with the throw keyword.

This is also the reason why it's a bad idea to rethrow the exception by doing throw ex; - you either want to use throw; (although careful about the issue of rethrowing in the same method that Xanatos pointed out), or you want to wrap the inner exception (ie. throw new MyException(ex)). In both cases, there's still some minor changes that can complicate debugging, but if you're well prepared, it helps a lot.

This behaviour is actually quite useful. For one, it means that you can have helper methods that construct exceptions for you to throw (this is used all over the place in .NET code itself). Two, it allows the runtime to actually throw exceptions like StackOverflowException and OutOfMemoryException - both have their instances created when the application starts, and when the issue occurs, they only throw - a new would fail, of course.