2013-10-04 252 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 
}