繁体   English   中英

重新抛出异常的正确方法

[英]Proper way to rethrow an exception

我在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"));
    }
}

Method3将由不同的方法调用,并且它返回Method3Exception,我需要将异常从Method2抛出到Method1,但是我不想在Method1上捕获Method3Exception。 最好的方法是什么?

有什么建议么

术语(重新)抛出通常是指将异常返回给调用方,以保留堆栈跟踪(其中包含异常发生的确切位置)。 可以使用throw;来完成throw; 没有指定与throw ex相反的异常操作数:

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

但是 ,如果您只想在该方法中添加一个之前没有任何内容的throw。 这是没有用的,只需删除try..catch,异常将传播到调用方,这是默认行为。

文件

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

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

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

因此,如果您所有的自定义异常都是这样,则可以将Method3的异常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的内部异常, 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
        }
    }
}

Method2 ,可以引发一个新的Method2Exception ,并将现有的Method3Exception作为其InnerException

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

然后,您可以捕获上面的Method2Exception

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

默认情况下例外是气泡。 例如,

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中 记录异常,但仍希望在ThirdMethod中处理异常,则必须选择:

第一种选择:

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

暂无
暂无

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

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