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

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

Vs:

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

当前回答

我肯定会用:

try
{
    //some code
}
catch
{
    //you should totally do something here, but feel free to rethrow
    //if you need to send the exception up the stack.
    throw;
}

这将保护您的堆栈。

其他回答

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

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

供参考,我刚刚测试了这个,'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()的调用导致了异常。

一些人实际上错过了非常重要的一点- 'throw'和'throw ex'可能做同样的事情,但他们没有给你一个关键的信息,即异常发生的行。

考虑下面的代码:

static void Main(string[] args)
{
    try
    {
        TestMe();
    }
    catch (Exception ex)
    {
        string ss = ex.ToString();
    }
}

static void TestMe()
{
    try
    {
        //here's some code that will generate an exception - line #17
    }
    catch (Exception ex)
    {
        //throw new ApplicationException(ex.ToString());
        throw ex; // line# 22
    }
}

当你执行'throw'或'throw ex'时,你会得到堆栈跟踪,但行#将是#22,所以你无法确定到底是哪一行抛出了异常(除非你在try块中只有1行或几行代码)。要在异常中获得预期的第17行,您必须抛出一个带有原始异常堆栈跟踪的新异常。

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

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

我肯定会用:

try
{
    //some code
}
catch
{
    //you should totally do something here, but feel free to rethrow
    //if you need to send the exception up the stack.
    throw;
}

这将保护您的堆栈。