正确的方法来重新抛出异常

时间:2016-07-29 05:09:48

标签: c# exception-handling

我在c#中有以下方法:

void Method1()
{
    try
    {
        Method2();
    }
    catch(Method2Exception ex)
    {
        //Log error
    }
}

void Method2()
{
    if(error)
    {
        throw(new Method2Exception("error"));
    }

    //Do something and call method3
    try
    {
        Method3();
    }
    catch(Method3Exception)
    {
        //??
    }
}

void Method3()
{
    //Do something
    if(error)
    {
        throw(new Method3Exception("error"));
    }
}

方法3它将被不同的方法调用,它返回Method3Exception,我需要重新抛出从Method2到Method1的异常,但我不希望在Method1上捕获Method3Exception。最好的方法是什么?

任何建议

4 个答案:

答案 0 :(得分:4)

术语(重新)抛出通常是指将异常抛回到调用者,保留堆栈跟踪(包含完全发生异常的位置)。这可以使用throw;完成,而不指定与throw ex相反的异常操作数:

try
{
    Method3();
}
catch(Method3Exception)
{
    throw;
}

然而,如果您只想在该方法中添加之前没有任何内容。它没用,只需删除try..catch,异常就会传播给调用者,这是默认行为。

Docs

  

可以在catch块中使用throw语句来重新抛出   捕获块被捕获的异常。在这种情况下,投掷   语句不带异常操作数。

答案 1 :(得分:3)

重新抛出异常的替代方法(使用其他答案中描述的throw;)是将异常包装在内部异常中。如MSDN中所述,所有自定义异常应至少有四个构造函数,其中一个是

public InvalidDepartmentException(string message, System.Exception inner) : base(message, inner) { }

因此,如果所有自定义异常都是这样的,您可以将Method3的异常包装为内部异常:

void Method2()
{
    if(error)
    {
        throw(new Method2Exception("error"));
    }

    //Do something and call method3
    try
    {
        Method3();
    }
    catch(Method3Exception exc)
    {
        throw new Method2Exception("error", exc); // exc is passed as inner exception
    }
}

然后,如果要检查Method1中的内部异常,可以使用属性InnerException

void Method1()
{
    try
    {
        Method2();
    }
    catch(Method2Exception ex)
    {
        if(ex.InnerException != null)
        {
            var message = ex.InnerException.Message;
            // Do what you need with the message
        }
    }
}

答案 2 :(得分:0)

Method2中,您可以使用现有Method2Exception作为Method3Exception投放新的InnerException

try
{
    Method3();
}
catch(Method3Exception method3Exception)
{
    throw new Method2Exception("Message", method3Exception);
}

然后你可以抓住上面的Method2Exception

try
{
    Method2();
}
catch(Method2Exception ex)
{
    //Log error
}

答案 3 :(得分:0)

默认情况下,异常会冒泡。例如,

void FirstMethod()
{
    int a = 0;
    int b = 10;
    int c = b / a;
}

void SecondMethod()
{
    FirstMethod();
}

void ThirdMethod()
{
    SecondMethod();
}

void FourthMethod()
{
    try
    {
        ThirdMethod();
    }
    catch (DivideByZeroException ex)
    {
        // Handle error
    } 
}

异常将发生在 FirstMethod 中,它会向上移动,并且会在 ForurthMethod 上显示。例如,如果你想在 ThirdMethod 记录例外,但仍希望在 FourthMethod 处理你的例外,那么你必须选择:< / p>

第一个选项:

void ThirdMethod()
{
    try
    {
        SecondMethod();
    }
    catch (Exception ex)
    {
        // Log the error
        throw; // Throw exception without affecting StackTrace
    }   
}

第二个选项:

在C#6.0之后,您可以使用异常过滤器轻松完成此操作。创建一个返回 false 的记录器方法。

bool Log(Exception ex)
{
    // Log the error
    return false;
}

在第三种方法中添加异常过滤器

void ThirdMethod()
{
    try
    {
        SecondMethod();
    }
    catch (Exception ex) when(Log(ex))
    {
        // Debugger won't reach here
    }   
}