抛出异常是一种好习惯吗?

时间:2016-05-20 00:36:04

标签: c# asp.net

考虑一个示例,其中用户使用两个aspx页面中的表单输入客户对象的值。使用第一种方法,在调用构造函数之前,aspx页面都需要验证ID大于0并且FirstName不为空。使用第二个选项,两个页面都可以调用Validate函数并向用户显示错误消息。

基于上面的例子,我更喜欢第二种选择。但是,当我在网上研究时,我一直看到它更加面向对象,立即抛出异常而不让对象接受无效数据。正如我之前所说的异常,每个调用此构造函数的页面都需要验证输入是否有效。我不喜欢重复逻辑,所以我更喜欢第二种选择。

域驱动设计的首选选项是什么?

选项1

public class Customer{

   public int ID { get; set; }
   public string FirstName { get; set; }

   public Customer(int ID, string FirstName){
      if (ID < 0)
          throw new Exception("ID cannot be less than 0");
      if (string.IsNullOrEmpty(FirstName))
          throw new Exception("First Name cannot be empty");

      this.ID = ID;
      this.FirstName = FirstName;
   }
}

选项2

public class Customer{

   public int ID { get; set; }
   public string FirstName { get; set; }

   public Customer(int ID, string FirstName){

      this.ID = ID;
      this.FirstName = FirstName;

   }

    public List<string> Validate(){
        List<string> ErrorMessages = new List<string>();

        if (ID < 0)
            ErrorMessages.Add("ID cannot be less than 0");
        if (string.IsNullOrEmpty(FirstName))
            ErrorMessages.Add("First Name cannot be empty");

        return ErrorMessages;
    }

}

3 个答案:

答案 0 :(得分:2)

我确信这个问题已在其他地方得到解答。但是这里有一些其他的阅读链接:

从“实用程序员”一书中,与例外用法有关的一个重要问题是“什么是例外?”。

在该部分中,我引用:

  

......例外应该很少用作程序正常流程的一部分;异常应保留用于意外事件。

虽然在你的情况下是否使用异常是有争议的,但我会说不 - 因为你可能需要在一个请求中捕获所有可能的输入错误并反映在表单上以供用户纠正值。

现在我记得,你应该在这里使用例外。这就是你代码防守的方式。如果您已经期望将有效参数传递给Customer类,那么代码应抛出异常以防止对类的无效使用(例如,由另一个程序员)。在这种情况下,您应该有另一个输入验证器来验证用户在到达Customer类之前对应用程序的输入。

答案 1 :(得分:1)

简短的回答是否定的。

如果应用程序无法继续执行错误数据,则会抛出异常。在您的示例中,逻辑是在前端显示错误消息,而选项2是用于实现此要求的更干净的方法。

抛出异常(即使它们被抓住)也是一项昂贵的操作。在线程可以继续之前,异常必须遍历整个调用堆栈。这将导致大规模的性能问题。

答案 2 :(得分:-1)

如果您有适当的异常处理,最好抛出异常。在应用程序崩溃之前,不要盲目地抛出异常。

在您的选项1示例中,ArgumentException更合适。

public Customer(int ID, string FirstName){
      if (ID < 0)
          throw new ArgumentException("ID cannot be less than 0");
      if (string.IsNullOrEmpty(FirstName))
          throw new ArgumentException("First Name cannot be empty");

      this.ID = ID;
      this.FirstName = FirstName;
   }

例如:

try
{
    Customer cust = new Customer(-1, string.Empty);
}
catch(ArgumentException aex)
{
    DoSomething(aex); // Log to database, file, or alike
    // Maybe display a message on the user
}
catch(Exception ex)
{
    DoSomething(ex); // Log to database, file, or alike
    // Do generic error process here
}

您的选项2更适合数据验证。应用DataAnnotations时,可以观察到该行为类似。不会抛出任何异常,但会返回错误消息。