【问题标题】:What exception to throw on invalid object state? [duplicate]在无效对象状态上抛出什么异常? [复制]
【发布时间】:2013-04-29 16:49:53
【问题描述】:

我总是错过了 c# 中的内置异常类型,这表明对象已损坏。在这种情况下你会扔什么?

当我意识到如果对象具有某种状态时,应该对对象起作用的方法将失败时,我通常会想念它。在这种情况下,我经常怀疑这种状态可能永远不会达到。但是出于防御考虑,我想抛出一个异常以防万一(例如,在未来的代码更改之后)。

对于方法参数,我们有ArgumentException,所以我们可以拒绝无效参数。但是对于对象状态呢?在 Java 中,我会使用 IllegalStateException

当然,您可以争辩说,实际上改变状态的方法可以检查状态的正确性。他们最好应该这样做,但如果他们不这样做(比如在传统的上帝课程中)?

编辑:

虽然InvalidOperationException 似乎是最合适的,但正如接受的答案所述(以及this one),请注意:

它很微妙,但在语义上它与InvalidOperationException 的含义不同。 InvalidOperationException 表示对象的“协议”中存在问题,调用者必须遵守(例如,未初始化、已关闭……)。在我的情况下,调用者没有做错任何事情,它是被破坏的对象。我想准确地传输该消息。

例子:

switch(this._someType) {
  case SomeType.A: doSomething(); break;
  case SomeType.B: doSomethingElse(); break;
  /*...*/
  default:
    // Unexpected type! Someone introduced a new type and didn't update this.
    throw new IllegalStateException("Unknown type "+this._someType); 
}

【问题讨论】:

  • 一般情况下,InvalidOperationException
  • 请参阅我对 Matthew Watsons 关于InvalidOperationException 的回答的评论。
  • 总体原则的一个更好的例子可能是尝试将一个项目Add 指向一个内部链表已损坏(例如,由于非法多线程使用)的字典对象。通常,从Add 方法抛出的InvalidOperatonException 表明已经添加了具有指定键的项,并且捕获此类异常的代码可能会认为这是真的。我认为,当对象的状态不适合它们时,抛出具有相关期望的类型的异常是非常糟糕的。

标签: c# .net exception


【解决方案1】:

你应该抛出 InvalidOperationException 来表明一个对象的状态无效。

来自 MSDN 文档(上面链接):

当方法调用对于对象的当前状态无效时引发的异常。

【讨论】:

  • 也许它很微妙,但从语义上讲,这有不同的含义。 InvalidOperationException 表示对象的“协议”中存在问题,调用者必须遵守该问题(例如,未初始化、已关闭……)。在我的例子中,调用者没有做错任何事情,它是broken的对象。我想准确地传输该消息。
  • @IgorLankin 在这种情况下,您可能需要Trace.Assert(someConditionThatMustBeTrue),因为如果您的代码被破坏,您就不会抛出任何有意义的异常来捕获它。这实际上是一个MyCodeIsBroken 异常!
  • (另一个想法)你仍然应该使用InvalidOperationException,因为这是你应该在.Net中使用的(即使考虑到你的区别,我完全理解) - 但你可以说在异常消息中确切地显示问题是什么,因此您不会丢失任何信息。
  • 我个人认为InvalidOperationException 被过度使用并且过于笼统,但它在.NET 中通常用于这种目的。您也可以定义自己的异常类型,但我想知道您所预期的哪些情况会不可避免地使您的对象首先进入损坏状态。也许更多的信息会有所启发?在没有太多背景信息的情况下,我的第一反应是,最好将精力花在预防这种情况上,而不是应对它。
  • 对,在很多情况下,断言可能是解决方案。
【解决方案2】:

我能想到的最接近 .Net 2.0 的类似物 [可能已经添加了更好的东西] 是 ObjectDisposedException,这表明一个对象已被置于永久无效状态 .这种异常可能被认为是“意外的”,但这是一件好事,因为它所指示的条件同样是意外的。此外,如果对象上的方法发现其状态无效,它应该在捕获尽可能多的有关对象状态的信息后,可能有助于故障排除,故意将对象置于永久无效状态,以便所有未来操作在它上面(可能除了请求提取出于故障排除目的而捕获的信息之外)将引发异常。

由于IDisposableObjectDisposedException 之间的强关联,最好定义一个新的异常类型,它可能会或可能不会从ObjectDisposedException 继承。可以说,ObjectDisposedException 应该是从 ObjectInvalidatedException 派生的,它也应该有 CorruptObjectDiscoveredExceptionCorruptObjectInvalidatedException [前者由第一个发现损坏的方法抛出,后者由随后的方法调用相同object],但我不确定它是否真的很重要。

我认为最重要的是确保有理由相信一个对象可能处于损坏状态的代码明确地使该对象无效。有些人建议发现意外问题的方法应该尝试关闭整个系统。我强烈反对这种哲学。如果一个方法将一个对象置于应该是临时损坏的状态,然后在对象的状态可以修复之前通过异常退出,它应该使对象完全无效,而不是让它损坏。如果在堆栈展开后系统在没有现在无效的对象的情况下无法运行,它将在短时间内崩溃(比在损坏状态下运行更好的选择)。但是,如果展开堆栈的过程导致损坏的对象被放弃(例如,有人试图从错误类型的文件中加载文档,导致LoadDocument 调用的方法中出现异常),则事实是now-abandoned object was corrupt 可能是了解引发异常的原因的有用信息,但可能不会对系统的整体运行状况产生不利影响。

【讨论】:

  • 好吧,如果我看到 ObjectDisposedException,如果它没有被抛出,我会非常惊讶,因为对已处置的对象调用了操作...
  • (续)但是,我必须强调,我真的希望有一个可以抛出的内置 ProgramLogicException,以及一个可以抛出它的 Assert.That(someConditionShouldBeTrue) 方法。
  • @MatthewWatson:异常处理本质上是一件棘手的事情;使用抛出异常的类型来决定谁应该捕获它的模式可能在像 C++ 这样没有硬编码到语言中的“特殊”类类型的语言的设计中是合理的,但它有一些限制Java 和 .NET 未能解决。尽管ObjectDisposedException 可能无法准确描述导致失败的原因,但在描述对象的状态时,它比我能想到的任何其他异常都更准确。
  • “它不提供调用者应该做什么的线索”是什么意思。当然,就其本质而言,程序逻辑故障不能提供这样的线索?如果某些内部逻辑应该为真,但不是——那么除了“哎呀——出了点问题”之外,你还能说什么?说“oogleflip 不能被去灵活化”只对实现代码有意义。但你至少可以附加一条人类可读的信息。
  • 我意识到我在谈论两种不同的情况 - 调用者尝试使用处于无效状态的对象的情况(例如 MoveNext() on修改集合的迭代器)。这是由调用代码中的错误引起的。另一种情况是发生了“不可能”的事情 - 实现代码中有一个错误(例如,我刚刚放入的那个列表现在是空的 wtf)。我的ProgramLogicException 是用于第二种情况,而对于第一种情况,我仍然认为InvalidOperationException 可以。
猜你喜欢
  • 2015-05-12
  • 1970-01-01
  • 1970-01-01
  • 2016-05-10
  • 2021-07-08
  • 2022-01-26
  • 2023-03-21
  • 2021-12-11
  • 2011-07-22
相关资源
最近更新 更多