为什么大多数异常忽略了特定于实例的信息

本文关键字:实例 信息 于实例 异常 大多数 为什么 | 更新日期: 2023-09-27 18:17:40

我注意到大多数异常消息都不包含特定于实例的详细信息,比如引起异常的值。它们通常只告诉你错误的"类别"。

例如,当尝试用第三类序列化对象时。派对图书馆,我得到一个MissingMethodException消息:

"没有为这个对象定义无参数构造函数。"

在很多情况下这就足够了,但是通常(在开发过程中)像

这样的消息

"没有为'Foo'类型对象定义无参数构造函数。"

可以直接引导您找到错误的原因,从而节省大量时间。

InvalidArgumentException是另一个例子:它通常告诉你参数的名称,但不告诉你它的值。这似乎是大多数框架引发的异常的情况,但也适用于第三方库。

这是故意的吗?

暴露内部状态(如变量的"错误"值)是否存在安全隐患?

为什么大多数异常忽略了特定于实例的信息

我能想到两个原因:

首先,可能引发异常的参数是传递给公共接口的值的处理形式。如果没有捕捉到重新抛出一个在大多数情况下都是相同的不同异常的代价,这个值可能就没有意义了。

其次,更重要的是,确实存在安全风险,很难事后猜测(如果我正在编写一个通用容器,我不知道它将在什么上下文中使用)。如果可以的话,我们不希望"信用卡:5555444455554444"出现在错误信息中。

最终,什么调试信息最有用将根据错误而变化。如果类型、方法和(如果可能的话)文件和行号还不够,那么是时候编写一些调试代码来捕获您想要知道的信息,而不是在下次您可能需要不同的信息(实例的字段状态可能和参数一样有用)时抱怨它还没有被捕获。

InvalidArgumentException和(per @Ian Nelson)"Key not found in dictionary"两者都有一些共同之处——不能保证框架能够找到合适的值显示给你——如果键/参数是任何用户定义的类型,并且ToString()没有被覆盖,那么你只会得到类型名称——它不会增加很多值。

异常主要用于程序消费。大多数程序不知道如何处理实例的信息。

Message属性是针对人类消费的。除了调试场景,人类不知道Foo是什么。

许多异常机制试图通过传递单个异常派生对象来满足各种正交目的:

  1. 让呼叫者知道各种特定的事情已经发生,或者存在各种特定的问题。
  2. 确定异常情况何时被"解决",以便正常的程序流程可以继续。
  3. 提供要告诉程序用户的指示
  4. 提供可以记录的信息,以便系统所有者在有安全日志可用时识别问题
  5. 提供可以记录的信息,允许系统所有者识别问题,但即使没有安全日志记录,也不会构成安全风险。

不幸的是,我不知道在广泛使用的任何异常机制实际上可以完成上述所有五个,