2010-10-08 84 views
15

我有一個方法,像...聲明一個方法總是拋出一個異常?

int f() { 
    try { 
    int i = process(); 
    return i; 
    } catch(Exception ex) { 
    ThrowSpecificFault(ex); 
    } 
} 

這將產生一個編譯器錯誤,「不是所有的代碼路徑返回一個值」。但在我的情況下,ThrowSpecificFault()將始終拋出(適當的)異常。所以我被迫在最後放置一個返回值,但這很醜陋。

這種模式的目的首先是因爲「process()」是對外部Web服務的調用,但需要翻譯各種不同的異常以匹配客戶端的預期接口(〜facade pattern我想) 。

任何更乾淨的方式來做到這一點?

+1

相關:[是否有標準的「從不返回」屬性的C#函數?](http://stackoverflow.com/questions/1999181/is-there-a-standard-never-returns-attribute-for-c函數) – 2010-10-08 17:42:19

回答

47

我建議你轉換到ThrowSpecificFault(ex)throw SpecificFault(ex); SpecificFault方法將返回拋出異常對象而不是拋出它自己。更乾淨。

這是由Microsoft's guidelines推薦的模式(找到「使用異常生成器方法」文本)。

+5

+1,這是微軟指南中推薦的模式。 – Joe 2010-10-08 17:43:45

+0

你有鏈接嗎? – noctonura 2010-10-08 17:55:15

+2

我這樣做:http://msdn.microsoft.com/en-us/library/seyhszts.aspx;找到「使用異常生成器方法」文本。 – CesarGon 2010-10-08 18:06:35

3

想像一下,如果在ThrowSpecificFault一個單獨的DLL中定義。 如果您修改DLL以避免引發異常,那麼運行您的程序時不要重新編譯它,會發生什麼情況?

+3

想象一下,如果方法Foo是在單獨的DLL中定義的。如果修改Foo返回一個long而不是int,那麼運行調用Foo的程序而不重新編譯它,會發生什麼? *沒什麼好的*。它永遠不會正確地改變外部庫中方法的簽名,然後繼續使用它而不用重新編譯。這就是爲什麼我們在組件上有版本印章等。 – 2010-10-08 18:49:00

+0

@Eric - 我相信SLaks的假設情況並不需要改變簽名,所以它不是一個明顯的突破性改變。 – kvb 2010-10-10 13:44:56

+2

@kvb:據我所知,建議的功能是捕獲一個事實,即一個方法在其簽名*中永遠不會返回*。 – 2010-10-10 15:32:36

8

這裏的問題是,如果你進入catchf()你的函數將永遠不會返回一個值。這會導致錯誤,因爲您將函數聲明爲int,這意味着您告訴編譯器您的方法將返回一個整數。

以下代碼將執行您正在查找的內容並始終返回一個整數。

int f() { 
    int i = 0; 
    try { 
    i = process(); 

    } catch(Exception ex) { 
    ThrowSpecificFault(ex); 
    } 
    return i; 
} 

把return語句放在函數的末尾,你會沒事的。

無論您的應用程序執行哪條執行路徑,確保您的方法始終會返回一個值總是一個好主意。

+0

+1你打我一分鐘! – 2010-10-08 17:42:02

1

如何:

int f() { 
int i = -1; 
try { 
    i = process();  
} catch(Exception ex) { 
    ThrowSpecificFault(ex); 
} 
return i; 
} 
+0

我要離開這個作爲答案,但羅伯特格雷納擊敗了我。 – 2010-10-08 17:42:54

2

你有三個選擇:

總是返回我,但前聲明它:

int f() { 
    int i = 0; // or some other meaningful default 
    try { 
     i = process(); 
    } catch(Exception ex) { 
     ThrowSpecificFault(ex); 
    } 
    return i; 
} 

返回從方法異常,並拋出:

int f() { 
    try { 
     int i = process(); 
     return i; 
    } catch(Exception ex) { 
     throw GenerateSpecificFaultException(ex); 
    } 
} 

或者創建一個自定義的Exception類並拋出:

int f() { 
    try { 
     int i = process(); 
     return i; 
    } catch(Exception ex) { 
     throw new SpecificFault(ex); 
    } 
} 
0

是的。

不要指望ThrowSpecificFault()拋出異常。讓它返回異常,然後把它扔到這裏。

它實際上更有意義。您不會爲「正常」流程使用異常,因此如果每次都拋出異常,則異常將成爲規則。在功能創建特定的異常,並在這裏把它,因爲它是一個例外,這裏的流量..

0

我想你可以做ThrowSpecificFault返回一個對象,然後你可以

return ThrowSpecificFault(ex)

否則,您可以將ThrowSpecificFault重寫爲Exception子類型的構造函數,也可以將ThrowSpecificFault創建爲創建該異常但不拋出異常的工廠。

3

你可以這樣做:

catch (Exception ex) 
{ 
    Exception e = CreateSpecificFault(ex); 
    throw e; 
} 
0

在你的情況下,但是這是你的知識不是編譯器。現在有方法可以肯定這種方法肯定會拋出一些令人討厭的異常。

試試這個

int f() { 
    try { 
    return process(); 
    } catch(Exception ex) { 
    ThrowSpecificFault(ex); 
    } 
    return -1; 
} 

您也可以使用throw關鍵字

int f() { 
    try { 
    return process(); 
    } catch(Exception ex) { 
    throw ThrowSpecificFault(ex); 
    } 
} 

但隨後這個方法應該返回一些異常,而不是把它扔的。

0

使用Unity.Interception來清理代碼。隨着攔截處理,你的代碼看起來是這樣的:

int f() 
{ 
    // no need to try-catch any more, here or anywhere else... 
    int i = process(); 
    return i; 
} 


所有你需要在下一步要做的就是定義一個攔截處理程序,它可以對異常處理度身訂製。使用這個處理程序,您可以處理在您的應用程序中拋出的所有異常。好處是你不再需要用try-catch塊來標記你的所有代碼。

public class MyCallHandler : ICallHandler, IDisposable 
{ 
    public IMethodReturn Invoke(IMethodInvocation input, 
     GetNextHandlerDelegate getNext) 
    { 
     // call the method 
     var methodReturn = getNext().Invoke(input, getNext); 

     // check if an exception was raised. 
     if (methodReturn.Exception != null) 
     { 
      // take the original exception and raise a new (correct) one... 
      CreateSpecificFault(methodReturn.Exception); 

      // set the original exception to null to avoid throwing yet another 
      // exception 
      methodReturn.Exception = null; 
     } 

     // complete the invoke... 
     return methodReturn; 
    } 
} 

向處理程序註冊類可以通過配置文件或編程方式完成。代碼非常簡單。註冊後,您實例使用Unity你的對象,像這樣:

var objectToUse = myUnityContainer.Resolve<MyObjectToUse>(); 

更多Unity.Interception:

http://msdn.microsoft.com/en-us/library/ff646991.aspx

7

現在返回類型可以是一個類型,或「無效」的意思「無返回類型」。理論上我們可以添加第二個特殊返回類型「never」,它具有您想要的語義。一個表達式語句的結束點由一個對「never」返回方法的調用組成,將被認爲是無法訪問的,因此在C#中的每個上下文中「goto」,「throw」或「return」合法的都是合法的。

現在很可能不會將它添加到類型系統中,十年以後。下次從零開始設計類型系統時,請記住包含「從不」類型。

相關問題