2013-10-04 253 views
1

說你打電話類似如下,你知道的方法只有永遠要扔的2個例外之一:最佳實踐

public static void ExceptionDemo(string input) 
{ 
    if (input == null) 
     throw new ArgumentNullException("input"); 

    if (input.Contains(",")) 
     throw new ArgumentException("input cannot contain the comma character"); 

    // ... 
    // ... Some really impressive code here 
    // ... 
} 

方法的一個活生生的例子這不,這是Membership.GetUser (String)

你會用下列哪調用的方法和處理異常:

方法1(檢查輸入參數第一首)

public static void Example1(string input) 
{ 
    // validate the input first and make sure that the exceptions could never occur 
    // no [try/catch] required 
    if (input != null && !input.Contains(",")) 
    { 
     ExceptionDemo(input); 
    } 
    else 
    { 
     Console.WriteLine("input cannot be null or contain the comma character"); 
    } 
} 

方法2(包裹呼叫一個try/catch)

public static void Example2(string input) 
{ 
    // try catch block with no validation of the input 
    try 
    { 
     ExceptionDemo(input); 
    } 
    catch (ArgumentNullException) 
    { 
     Console.WriteLine("input cannot be null"); 
    } 
    catch (ArgumentException) 
    { 
     Console.WriteLine("input cannot contain the comma character"); 
    } 
} 

我已經教過幾年這兩種方法,並想知道一般最佳的做法是這種情況。

更新 一些海報注重方法拋出這些異常,正在處理的異常,而不是辦法,所以我提供(Membership.GetUser (String)其行爲以同樣的方式一個.NET Framework方法的一個例子) 因此,爲了澄清我的問題,如果您打電話給Membership.GetUser(input),您將如何處理可能的例外情況,方法1,2或其他?

感謝

+2

當然方法一例外是昂貴的,在這種情況下,你可以避開他們用一個簡單的檢查。 –

+2

對於預期的程序行爲,不應該發生異常,只是爲了例外(這就是爲什麼他們被稱爲異常)的情況,而這些情況並不是預期的。 – helb

回答

1

這取決於,但通常呈現方法都不是好的。如前所述,在第一種情況下,您正在複製代碼。第二,你正在捕捉異常而沒有對它做任何事情 - 甚至沒有重新拋出,只是吞下它。如果你只想記錄它或顯示一些消息,通常你應該使用AppDomain.UnhandledException來實現一個全局處理程序/記錄器,並在那裏執行;這樣,你不必用不必要的try/catch塊污染你的代碼。

這裏真正的問題是輸入爲空還是包含','在您的特定情況下確實是一種特殊行爲 - 例如如果這是一些GUI輸入的字符串,那麼這通常不會導致異常拋出(應該預期最終用戶錯誤)並且應該被適當地處理(例如,帶有重新輸入輸入的警告)。在這種情況下,使用if語句驗證輸入是正確的方法。但是,如果輸入爲空或包含','是一個實際的例外行爲(例如,指示某個東西已損壞或丟失的API問題),則引發異常是可以的。在這種情況下,您可以簡單地撥打ExceptionDemo(input)而無需嘗試/捕獲。如果你想實際上對異常做些什麼(例如以某種方式改變輸入),那麼使用try/catch。

+0

我認爲這是對我最有意義的解釋。我用一個框架方法的例子更新了這個問題,它拋出了我例子中提到的異常,這是否會改變你的看法? – philreed

+0

抱歉,遲到的回覆。它將取決於調用'GetUser()'的上下文 - 例如用戶是否將用戶名輸入到文本框中?在這種情況下,我(注意有些人可能不同意)會在調用GetUser()之前使用第一種方法('if')驗證輸入,因爲預期會發生拼寫錯誤。然而,說用戶名是一個從數據庫中檢索的字符串,並且應該已經有效 - 在這種情況下,我會使用try/catch,因爲包含或爲空的字符串將指示某些數據庫操作問題,即例外行爲。 – w128

+0

很好的解釋,非常感謝。 – philreed

0

調用者不應承擔有關他們調用代碼任何東西。

你的第一個例子是不好的,因爲你重複代碼:來電者執行幾乎string.INOE() VS string == null)相同的檢查作爲被叫方(直到它們的變化)。

第二個例子非常糟糕,因爲它忽略了拋出的異常並給它們自己的解釋。

像往常一樣:這取決於。如果您有一個正確的分層應用程序,其中方法調用位於您的UI層中,您只需要捕獲該方法拋出的異常:您需要將這些錯誤顯示給用戶。

0

這取決於ExceptionDemo被調用的次數以及接觸的人數。如果它被廣泛使用,那麼在調用ExceptionDemo之前,當您知道(並記錄)ExceptionDemo執行檢查之前,您不希望檢查條件。

鑑於返回類型是void,如果輸入錯誤,那麼將ExceptionDemo更改爲不起作用呢?

(你有沒有注意到,你是在方法1更嚴格的 - 空字符串不是有效的輸入,但在方法二是)

+1

「你有沒有注意到你在方法1中更嚴格」 - >看上去很好,這是我的一個疏忽。 – philreed

0

我會推薦標準,通用結構如下:

public static void Operation(object input) 
{ 
    try 
    { 
     ValidateInput(input); 
     //Do Operation 
    } 
    catch (MySpecificException subSubExceptionType) //Catch most specific exceptions 
    { 

     //Log or process exception 
     throw; 
    } 
    catch (MySpecificException subExceptionType) //Catch specific exception 
    { 
     //Log or process exception 
    } 
    catch (Exception exceptionType) //Catch most generic exception 
    { 

     //Log or process exception 
    } 
    finally 
    { 
     //Release the resources 
    } 
} 

private static void ValidateInput(object input) 
{ 
    if(input == null) 
     throw new NoNullAllowedException(); 
    //Check if properties of input are as expected. If not as expected then throw specific exception with specific message 
}