在捕获异常并重新抛出异常时,应该考虑哪些最佳实践?我想确保Exception对象的InnerException和堆栈跟踪被保留。下面的代码块在处理这个问题的方式上有区别吗?

try
{
    //some code
}
catch (Exception ex)
{
    throw ex;
}

Vs:

try
{
    //some code
}
catch
{
    throw;
}

当前回答

你也可以使用:

try
{
// Dangerous code
}
finally
{
// clean up, or do nothing
}

而抛出的任何异常都将上升到处理它们的下一层。

其他回答

供参考,我刚刚测试了这个,'throw;'报告的堆栈跟踪不是完全正确的堆栈跟踪。例子:

    private void foo()
    {
        try
        {
            bar(3);
            bar(2);
            bar(1);
            bar(0);
        }
        catch(DivideByZeroException)
        {
            //log message and rethrow...
            throw;
        }
    }

    private void bar(int b)
    {
        int a = 1;
        int c = a/b;  // Generate divide by zero exception.
    }

堆栈跟踪正确地指向异常的起源(报告的行号),但为foo()报告的行号是抛出的行;语句,因此您无法判断是哪个对bar()的调用导致了异常。

经验法则是避免捕获和抛出基本的Exception对象。这迫使你对异常更加聪明;换句话说,你应该有一个显式的SqlException捕捉,这样你的处理代码就不会对NullReferenceException做错误的事情。

不过,在现实世界中,捕获和记录基本异常也是一种很好的实践,但不要忘记遍历整个过程以获取可能存在的任何innerexception。

没有人解释过ExceptionDispatchInfo之间的区别。Capture(ex). throw()和一个普通的throw,所以它在这里。然而,有些人已经注意到了投掷的问题。

重新抛出捕获的异常的完整方法是使用ExceptionDispatchInfo。Capture(ex). throw()(仅在. net 4.5中可用)。

下面是测试这一点的必要情况:

1.

void CallingMethod()
{
    //try
    {
        throw new Exception( "TEST" );
    }
    //catch
    {
    //    throw;
    }
}

2.

void CallingMethod()
{
    try
    {
        throw new Exception( "TEST" );
    }
    catch( Exception ex )
    {
        ExceptionDispatchInfo.Capture( ex ).Throw();
        throw; // So the compiler doesn't complain about methods which don't either return or throw.
    }
}

3.

void CallingMethod()
{
    try
    {
        throw new Exception( "TEST" );
    }
    catch
    {
        throw;
    }
}

4.

void CallingMethod()
{
    try
    {
        throw new Exception( "TEST" );
    }
    catch( Exception ex )
    {
        throw new Exception( "RETHROW", ex );
    }
}

案例1和案例2将为您提供一个堆栈跟踪,其中CallingMethod方法的源代码行号是抛出新异常(“TEST”)行的行号。

然而,情形3将为您提供一个堆栈跟踪,其中CallingMethod方法的源代码行号是抛出调用的行号。这意味着如果抛出新的异常(“TEST”)行被其他操作包围,则您不知道异常实际上是在第几行抛出的。

情况4与情况2类似,因为原始异常的行号被保留,但不是真正的重抛出,因为它改变了原始异常的类型。

如果你抛出一个带有初始异常的新异常,你也会保留初始堆栈跟踪。

try{
} 
catch(Exception ex){
     throw new MoreDescriptiveException("here is what was happening", ex);
}

当抛出ex时,实际上是抛出了一个新的异常,并将错过原始的堆栈跟踪信息。Throw是首选的方法。