Skip to content

文章

抛出异常时的注意事项

2013年3月21日 • 3 分钟阅读

抛出异常时的注意事项

一位同事发来了一封邮件,其中包含一些他正在苦苦思索的代码。他试图避免使用 try/catches 来驱动业务逻辑。

问题不在于 try/catches,它只是问题的症状。你能发现问题所在吗?你需要做一些假设,但我相信你会得出与我相同的结论。

代码如下;为了保护无辜者,我对其进行了修改:

private Customer GetOrCreateCustomer(long customerTelephoneNumberOrCustomerId)
        {
           Customer customer;
            try
            {
                customer = this.DoMagic(customerMasterTelephoneNumberOrCustomerId);
            }
            catch (DataException)
            {
                try
                {
                    //TODO: I know this isn't ideal. Still thinking of a better way to do this. 
                    customer = this. GetCustomer(customerMasterTelephoneNumberOrCustomerId);
                }
                catch (DataException)
                {
                    customer = this.GetCustomerFromExternal(customerMasterTelephoneNumberOrCustomerId);
                    customer.CustomerId = this.CreateCustomer(customer);
                }
            }

            return customer;
        }

这个系统中有一个潜在的哲学理念,即空值是不好的。在大多数可能产生空值的情况下,都会抛出异常。起初我没有看出这有什么问题。我将其视为一个架构决策,一种美学选择,但当我与代码交互时,我发现这显然是一个架构错误。

你可能会问,为什么在空值情况下抛出异常是不好的?

以下是考虑抛出异常时的一些指导原则:

  1. 你必须检查空值才能抛出异常这一事实应该提示你这是不必要的。这是一个预期的结果,因此不是异常。
  2. 抛出异常是一个资源密集型操作,是 .Net 中可以执行的最耗费资源的操作之一。
  3. 异常就是异常。它是对代码中所做假设的异常——当这些假设被打破时,系统必须终止,它无法继续运行,因为系统处于未知状态(即数据库不再可用),这也可能是一个攻击向量。
  4. 抛出异常意味着你必须将上游调用包装在 try/catch 块中以强制执行业务规则。空值是控制应用程序流程的业务机会。对空值的操作应该在必须做出业务决策的地方进行。例如,客户变量为空,在 UI 层向用户显示一条消息,说明无法找到 id 为 ‘1234’ 的客户。

作者:Chuck Conway 专注于软件工程和生成式人工智能。在社交媒体上与他联系:X (@chuckconway) 或访问他的 YouTube

↑ 回到顶部

您可能还喜欢