簡體   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