如果需要,使用许多业务异常是否正常?

时间:2013-07-31 11:24:04

标签: c# architecture exception-handling

即使应用程序需要很多自定义异常,定义和抛出自定义异常是一个好习惯吗?

  • EntityNotFoundException
  • EntityAlreadyExistsException
  • EntityNotUniqueException
  • EntityNotAddedException
  • EntityNotUpdatedException
  • EntityNotDeletedException
  • QuizOverException
  • QuizExpiredException
  • TableAlreadyBookedException
  • EndDateMustBeGreaterThanStartDateException

我试着将这些示例异常名称命名为尽可能好地描述它们的目的。我希望他们能够形成我想要问的想法。

不要仅仅考虑这些例外情况来限制你的想象力,而是在应用程序生命期间可能出现的所有情况。考虑CRUD和业务异常。

我知道抛出和捕获异常在性能方面是一个昂贵的过程,但它们不能提供更优雅的方式来开发您的应用程序吗?

  • 抛出EntityNotFoundException而不是编写if语句来检查实体是否为空是不是更好?
  • 抛出EntityAlreadyExistsException而不是写一个额外的if语句来调用一个方法来检查具有给定Id的实体是否已经存在,这不是更好吗?
  • 抛出EntityNotAddedException而不是检查bool类型的返回值来指定事务是否成功不是更好吗?如果我们想要返回一个对象怎么办?

我觉得答案就像是“你不应该使用EntityNotFoundException,而是检查是否为null,但你应该使用EntityAlreadyExistsException”,“没有圣杯”。

我想知道这样做的优雅方式是什么?

4 个答案:

答案 0 :(得分:5)

请注意,异常应该代表特殊情况,所有问题都只能通过以下方式得到解答 - 取决于

何时&你打算抛出特定异常的地方自然会决定它是否有意义。例如,如果您尝试检索应该但不存在的实体,那么抛出EntityNotFoundException将被认为是合适的,因为我们现在有一个例外环境。另一方面,如果你在创建新实体之前检查实体是否已经存在,那么你可以争辩说,因为我们知道实体可能存在或者可能不存在,那么它实际上并不是特殊情况。

就像我说的那样,它实际上取决于情境的上下文和应用程序的性质是否应该抛出异常,但是,你最不想做的一件事是控制程序流程有例外。

为了帮助区分何时适合使用异常与业务逻辑,只需问自己“这种特殊情况是否有效?”或换句话说“是否可以应用程序发现自己处于这种状态?“。如果答案是肯定的,则使用逻辑来控制应用程序的流程并处理这种情况,否则你想抛出一个Exception来有效地中断程序流程并告知用户某些东西不太正确。

答案 1 :(得分:2)

创建例外时询问其附加值。 有人会关心特定类型的异常吗? 异常会有不同的字段来帮助异常处理吗? 使用自定义消息的更抽象的异常可以节省您编写没有值的异常的时间。

使用异常来控制程序流被认为是个坏主意。以下是一些原因:

  • 已为错误处理概念创建了例外
  • 你说的表现
  • 你可以忘记处理一些例外
  • 如果使用已检查的异常,则可能需要为不关心或不知道如何处理的异常编写处理程序。
  • 异常会增加程序中的不确定性(异常处理时引发的异常,最后语句,......)

还有其他方法可以解决条件语句,看看scala编程语言及其对“monads”的使用。

答案 2 :(得分:2)

C ++中的异常处理范例的一个主要限制是由Java和随后的.NET继承,如果对Foo的调用抛出BozException,则可能有两个非常不同含义:

  • 在执行Foo期间检测到某些条件,这意味着它应该抛出BozException

  • Foo调用了一些不期望抛出BozException的方法,但是方法仍抛出一个而Foo没有捕获它,异常被抛出{{ 1}}。

即使框架指南阻止在现有异常看似“适合”时使用自定义异常,但是缺少任何标准手段来捕获框架定义的异常,以了解它是否实际上代表了预期的情况。使用Framework异常(如Foo)来报告调用者可能想要处理的业务逻辑环境(例如,尝试向具有相同ID的记录添加InvalidOperationException)是一个相当大的缺点。如果你可以容忍与定义异常相关的样板,我建议最好在太多而不是太少的情况下犯错(尽管你可能希望对可能以相同方式处理的异常使用继承)。

答案 3 :(得分:1)

与软件开发中的几乎所有内容一样,根据一般规则或最佳实践,该技能知道何时以及如何应用它。

我应该编程到界面吗?是!我是否应该为每个单独的类编写实现相应的接口并且只对该抽象进行编程?我能做到,但写一个非常简单的应用程序会花费我一个年龄,我的工作效率会停滞不前。

单一责任 - 这是一件好事吗?是!我写的每个班级都只有一个且只有一个责任。不 - 部分是因为我自己作为程序员的失败,但也因为我最终会遇到过多的单方法类和无法管理的断开代码库。

现在让我们转向错误处理:

首先,通过查看您对James'回答的评论,让我们澄清一下,使用error codesexception handling代表了应用程序中处理错误的两种不同模型,作为一般规则,不应该混在一起。

让我们假设您正在使用异常处理并生成以下参数:

为什么我们会抛出异常?

我们抛出一个异常,因为发生了一些不好的事情。如果我们期望某个场景出现在某个点上,那么它就在我们的应用程序流程中,因此并不例外 - 因此抛出Exception是不合适的!

使用此参数,抛出除顶级Exception类之外的任何内容都没有意义,因为任何其他异常都意味着我们已经预见到了这种情况并且能够将额外的元数据附加到异常。 / p>

为什么要处理异常?

抛出异常之后,我们希望有人在某处处理它,希望有意将应用程序恢复到一致状态。但是,如果异常真的例外 - 我们无法知道哪个状态已被破坏,因此异常处理是徒劳的。

这不是太过分了吗?

嗯 - 这正是错误处理在面向服务的体系结构中的工作原理。一个强大的服务不应该揭示发生异常时发生的事情的任何有罪的细节(这是一个安全漏洞并引入服务和客户端之间的耦合) - 所有客户端需要知道的是发生了一些不好的事情

但是,我猜我们正在面向对象的环境中工作,我们准备接受实现与其消费者之间稍高程度的耦合。这就是重要的一点 - 通过引入一个异常层次结构来公开有关异常的详细信息,以增加应用程序中的耦合(消费者需要详细了解所有可能的例外情况)扔)。

在软件中,我们努力寻找松散耦合的代码库,使其易于维护和扩展。毫无疑问,在异常的SOA方法与您在问题中描述的方法之间存在一种幸福的媒介 - 发现甜蜜点是开发人员的技能。