我在 Eiffel 中找不到任何实质性的错误处理示例。我只找到了一些例子,要么是微不足道的,要么完全忽略错误,或者将错误处理留给读者。我有兴趣了解在没有异常的情况下错误如何通过调用堆栈。例如,我想知道发送网络请求的应用程序如何通知用户在调用链中检测到的网络问题。类似的东西。
--
编辑:我确实知道 Eiffel 中错误处理的基础知识(状态和异常)。但是,我找不到任何关于应用程序如何通过状态处理错误的实质性示例。故障状态如何链接?
我在 Eiffel 中找不到任何实质性的错误处理示例。我只找到了一些例子,要么是微不足道的,要么完全忽略错误,或者将错误处理留给读者。我有兴趣了解在没有异常的情况下错误如何通过调用堆栈。例如,我想知道发送网络请求的应用程序如何通知用户在调用链中检测到的网络问题。类似的东西。
--
编辑:我确实知道 Eiffel 中错误处理的基础知识(状态和异常)。但是,我找不到任何关于应用程序如何通过状态处理错误的实质性示例。故障状态如何链接?
Eiffel 提倡使用对象状态而不是异常。在这种情况下,客户可能会弄清楚他们在发生错误时的期望并正确处理它。例如,
has_error: BOOLEAN
-- Has operation terminated with an error?
error_code: INTEGER
-- Last error code or `no_error'.
is_closed: BOOLEAN
-- Is connection closed?
response: detachable RESPONCE
-- Last response if `not has_error'.
send_request (data: REQUEST)
require
is_open: not is_closed
do
...
ensure
is_closed: is_closed implies (has_error and not connection.is_open)
is_successful: not has_error implies attached response
end
然后客户端可以推断供应商对象的状态并以可预测的方式继续使用它:
interface.send_request (...)
if interface.is_closed then
... -- The connection is unusable and should be reestablished.
elseif interface.has_error then
... -- Inspect `interface.error_code', possibly trying to resend the request.
else
... -- Use `interface.response' to continue processing.
end
在存在例外的情况下,除了一些文档之外,人们无法推断在什么情况下应该做什么。此外,它还阻止使用可以轻松检查response
上述代码中的使用是否完全有效的自动工具。
如果堆栈深处发生错误,则可以使用异常机制与rescue
/ retry
。然而,它可能会在低级网络组件和与网络故障细节无关的用户界面之间引入紧密耦合。在最简单的情况下,网络类将{EXCEPTIONS}.raise
使用适当的消息进行调用。更具体的方法是创建一个类型的对象EXCEPTION
(或后代),通过调用它来设置相应的消息set_description
,并通过调用raise
. 处理异常的用户代码可能如下所示。
local
is_retried: BOOLEAN
e: EXCEPTIONS
do
if is_retried then
-- There was an exception, handle it.
create e
if e.developer_exception_name ~ "This error" then
... -- Do something.
elseif e.developer_exception_name ~ "That error" then
... -- Do something else.
else
... -- Report yet another error.
end
else
... -- Some code that may fail with an exception.
end
rescue
if not is_retried then
is_retried := True
retry
end
end
编辑
处理嵌套错误的特定方法取决于应用程序设计,并且似乎与语言无关。可能的替代方案是:
(如果使用异常机制,不推荐。)在捕获(低级)异常并处理它以恢复类不变量后,会引发新的异常而不取消先前的异常。然后{EXCEPTION}.cause
可以(递归地)使用查询来访问嵌套的异常对象。
可以使用与前一种类似的机制。但是,一个类可以将详细信息请求委托给较低级别的类,而不是创建新对象。例如,
class A feature
has_error: BOOLEAN
do
Result := nested.has_error
end
error: STRING
do
Result := "Cannot complete operation X. Reason: " + nested.error
end
feature {NONE}
nested: B
end
class B feature
has_error: BOOLEAN
do
Result := nested.has_error
end
error: STRING
do
Result := "Cannot complete operation Y. Reason: " + nested.error
end
feature {NONE}
nested: C
end
可以使用日志记录工具。他们可以区分错误严重性、指定来源等。
class A feature
do_something
do
nested.whatever
if nested.has_error then
log.error ("Cannot complete operation X.")
end
end
has_error: BOOLEAN do Result := nested.has_error end
feature {NONE}
nested: B
end
class B feature
whatever
do
nested.try_something
if nested.has_error then
-- An error has been reported by "nested".
elseif something_else_goes_wrong then
has_inner_error := True
log.error ("Something goes wrong.")
elseif has_minor_issues then
log.warning ("Be careful.")
end
end
has_error: BOOLEAN do Result := nested.has_error or has_inner_error end
has_inner_error: BOOLEAN
-- Some error that is not one of the errors reported by `nested'.
feature {NONE}
nested: C
end
除了 Alexander 的回答,有时使用异常也很方便。在 Eiffel 中,我们不倾向于捕获它们(通常类不变量已变得无效),但对于某些应用程序,您只是不想处理错误。如果出现错误,您只需停止,并依靠程序外部的东西重试。使用这种方法的库的例子是 ecli 和 eposix。