简体   繁体   English

重新抛出异常的正确方法

[英]Proper way to rethrow an exception

I have the following methods in c#: 我在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 its gonna be call by different methods and it returns Method3Exception and I need rethrow the exception from Method2 to Method1 but I don't want catch Method3Exception on Method1. Method3将由不同的方法调用,并且它返回Method3Exception,我需要将异常从Method2抛出到Method1,但是我不想在Method1上捕获Method3Exception。 what's the best way to do that? 最好的方法是什么?

Any suggestions 有什么建议么

The term (re)throw usally refer to throwing the exception back to the caller preserving the stack trace (which contains where the exception exactly occurred). 术语(重新)抛出通常是指将异常返回给调用方,以保留堆栈跟踪(其中包含异常发生的确切位置)。 This can be done using throw; 可以使用throw;来完成throw; without specifying the exception operand contrary to throw ex : 没有指定与throw ex相反的异常操作数:

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

However , if you're just going to add a throw with nothing before it in that method. 但是 ,如果您只想在该方法中添加一个之前没有任何内容的throw。 It is useless, just remove the try..catch and the exception is going to propagate to the caller which is the default behavior. 这是没有用的,只需删除try..catch,异常将传播到调用方,这是默认行为。

Docs : 文件

A throw statement can be used in a catch block to re-throw the exception that the catch block caught. 在catch块中可以使用throw语句重新抛出catch块捕获的异常。 In this case, the throw statement does not take an exception operand. 在这种情况下,throw语句不采用异常操作数。

Alternative way to re-throwing the exception (using throw; as described in other answers) is to wrap the exception in inner exception. 重新抛出异常的另一种方法(使用throw;如其他答案所述)是将异常包装在内部异常中。 As described in MSDN , all custom exceptions should have at least four constructors, and one of them is MSDN中所述 ,所有自定义异常都应至少具有四个构造函数,其中之一是

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

So if all your custom exceptions are like this, you could wrap the exception from Method3 as inner exception: 因此,如果您所有的自定义异常都是这样,则可以将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
    }
}

Then if you want to inspect the inner exception in Method1 , you can use property InnerException : 然后,如果要检查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
        }
    }
}

In Method2 , you can throw a new Method2Exception with the existing Method3Exception as its InnerException : Method2 ,可以引发一个新的Method2Exception ,并将现有的Method3Exception作为其InnerException

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

Then you can catch the Method2Exception above: 然后,您可以捕获上面的Method2Exception

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

Exceptions are bubbles up by default. 默认情况下例外是气泡。 For example, 例如,

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

The exception will occur in FirstMethod and it will go upwards and will be cought at ForurthMethod . 异常将在FirstMethod中发生,并且会上升,并将在ForurthMethod中进行处理 If you want to log the exception at ThirdMethod for example, but still want your exception to be handled at FourthMethod then you have to options: 例如,如果要在ThirdMethod中 记录异常,但仍希望在ThirdMethod中处理异常,则必须选择:

First option: 第一种选择:

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

Second option: 第二种选择:

After C# 6.0 you can do this with ease by using exception filters. 在C#6.0之后,您可以通过使用异常过滤器轻松地做到这一点。 Create a logger method which returns false . 创建一个返回false的记录器方法。

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

Add exception filter in third method: 在第三个方法中添加异常过滤器

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