异常处理和安全编码的最佳实践

时间:2013-10-04 08:50:40

标签: c# exception exception-handling

假设您正在调用类似于以下的方法,您知道它只会抛出以下两种情况之一:

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");
    }
}

这些年来我已经掌握了这两种方法,并想知道这种情况的一般最佳实践是什么。

更新 有几张海报专注于抛出异常的方法,而不是处理这些异常的方式,所以我提供了一个.Net Framework方法的例子,其行为方式相同(Membership.GetUser (String)) 所以,为了澄清我的问题,如果我们正在调用Membership.GetUser(input)你将如何处理可能的异常,方法1,2或其他什么?

由于

4 个答案:

答案 0 :(得分:1)

这取决于,但一般来说,两种方法都不是很好。如前所述,在第一种情况下,您正在复制代码。在第二种情况下,你正在捕捉异常,而没有真正做任何事情 - 甚至没有重新抛出,只是吞下它。如果您只想记录它或显示一些消息,通常您应该使用AppDomain.UnhandledException实现全局处理程序/记录器并在那里执行;这样,您就不必使用不必要的try / catch块污染您的代码。

这里真正的问题是输入是否为空或包含','在您的特定情况下是否真的是一种例外行为 - 例如如果这是一些GUI输入的字符串,那么这通常不应该导致异常抛出(应该预期最终用户错误)并且应该适当地处理(例如,警告重新输入输入)。在这种情况下,使用if语句来验证输入是正确的方法。但是,如果输入为null或包含','是一个实际的异常行为(例如,指示某些内容已损坏或丢失的API问题),则抛出异常即可。在这种情况下,您可以简单地调用ExceptionDemo(input)而不使用try / catch。如果你想真正对异常做一些事情(例如以某种方式改变输入),那么使用try / catch。

答案 1 :(得分:0)

来电者不应该对他们正在呼叫的代码采取任何行动。

你的第一个例子很糟糕,因为你正在复制代码:调用者执行几乎string.INOE() vs string == null)与被调用者相同的检查(直到他们改变了。)

第二个例子非常糟糕,因为它忽略了抛出的异常,并给出了自己的解释。

像往常一样:这取决于。如果你有一个正确分层的应用程序,方法调用在你的UI层,你想要捕获方法抛出的异常:你将要向用户显示这些错误。

答案 2 :(得分:0)

这取决于ExceptionDemo被调用的次数以及它被暴露的次数。如果它被广泛使用,那么在调用ExceptionDemo之前你不想检查条件,当你知道(并记录)ExceptionDemo无论如何都要进行检查时。

鉴于返回类型为void,如果输入错误,将ExceptionDemo更改为无效?

(您是否注意到在方法1中更严格 - 空字符串不是有效输入,但在方法2中它是)

答案 3 :(得分: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
}