【问题标题】:Best practices for exception handling and safe coding异常处理和安全编码的最佳实践
【发布时间】:2013-10-04 18:41:14
【问题描述】:

假设您正在调用类似于以下的方法,您知道该方法只会引发 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)

您会使用以下哪项来调用方法并处理异常:

方法一(先检查输入参数)

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 或其他什么?

谢谢

【问题讨论】:

  • Method1 当然异常是昂贵的,在这种情况下你可以通过简单的检查来避免它们。
  • 对于预期的程序行为不应发生异常,仅适用于无法预见的异常(这就是它们被称为异常的原因)情况。

标签: c# exception exception-handling


【解决方案1】:

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

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

【讨论】:

  • 我认为这是对我来说最有意义的解释。我已经用一个框架方法的例子更新了这个问题,它抛出了我的例子中提到的异常,这会改变你的看法吗?
  • 抱歉回复晚了。这将取决于调用 GetUser() 的上下文 - 例如用户是否在文本框中输入用户名?在这种情况下,我(请注意,有些人可能不同意)将在 GetUser() 调用之前使用第一种方法 (if) 验证输入,因为预计会出现拼写错误。但是,假设用户名是从数据库中检索到的字符串,并且应该已经有效 - 在这种情况下,我将使用 try/catch,因为包含 或为 null 的字符串表示某些数据库操作问题,即异常行为。
【解决方案2】:

调用者不应假设他们正在调用的代码。

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

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

像往常一样:这取决于。如果您有一个适当分层的应用程序,其中方法调用位于您的 UI 层中,您确实只想捕获方法抛出的异常:您需要向用户显示这些错误。 p>

【讨论】:

    【解决方案3】:

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

    给定返回类型为void,如果输入错误,将ExceptionDemo改成无效怎么办?

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

    【讨论】:

    • “您是否注意到您在方法 1 中更严格了”--> 发现得很好,是我的疏忽。
    【解决方案4】:

    我会推荐如下标准和通用结构:

    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
    }
    

    【讨论】:

      猜你喜欢
      • 2018-01-03
      • 1970-01-01
      • 1970-01-01
      • 2017-05-11
      • 2013-05-09
      • 2011-11-10
      • 1970-01-01
      • 2013-04-22
      相关资源
      最近更新 更多