1

我相信在大多数情况下,当异常发生时,它们确实发生在对象周围,由于尝试调用对象上的方法,或者它们发生在执行属于某个对象的某个方法的某些代码时。

我如何从给定的Exception实例中知道这个对象?

例子

begin
  ....
rescue ActiveRecord::SerializationTypeMismatch => e
  object = e.some_method_which_will_return_active_record_object
rescue => e
  object = e.get_me_object_around_which_this_happened
end

在我的特殊情况下,我想知道发生了哪个 AR 对象 SerializationTypeMismatch。

在这种情况下,我对 e.message 或 backtrace 不感兴趣,我也检查了 e.methods,但没有找到知道关联对象的方法。

4

1 回答 1

2

我相信在大多数情况下,当异常发生时,它们确实发生在对象周围,由于尝试调用对象上的方法,或者它们发生在执行属于某个对象的某个方法的某些代码时。

但这并非在所有情况下都是正确的,并且通常在引发的异常和它发生的“周围”对象之间没有关系,因为可能并不总是有一个对象。

例如,当所需文件(例如 Ruby 脚本)无法加载时,会引发LoadError 。这实际上与任何特定的对象实例无关。我不相信任何标准异常类的初始化方法都接受用于存储与该异常相关的对象的参数,因此没有直接的方法可以映射回原始对象。

如果您无法映射回发生错误的 ActiveRecord 对象,则您的begin/rescue块可能在被调用的代码堆栈中放置“太高”。例如,您的块中可能有类似这样each的循环begin

begin
  items.each do |item|
    raise RuntimeError unless item == "foo"
  end
rescue RuntimeError => e
  # which item caused the error?
end

在那种情况下,您无法知道哪个项目导致了错误,但您可以重组您的begin块以更直接地包装代码,如下所示:

items.each do |item|
  begin
    raise RuntimeError unless item == "foo"
  rescue RuntimeError => e
    # the object that raised the exception must be 'item'
  end
end

这当然是一个人为的例子,但希望它说明了将begin/rescue块更紧密地包装在可能引发异常的代码周围的技术,因此对于哪个对象导致问题没有歧义。

于 2013-04-03T06:57:55.153 回答