在父方法上救援在子方法中引发异常



Ruby中有什么方法可以基于继承的标准救援策略吗?

我想要这样的东西:

class Parent
def method
rescue StandardError => e
#handle error
end
end
class Child < Parent
def method
raise StandardError.new("ERROR") if error_present
#do some stuff
super
end
def error_present
#checks for errors
end
end

我期望的结果是,当StandardError在孩子的方法中提出时,它将从父的方法定义中拯救出来。

如果这是不可能的,我还有其他方法可以实现这种行为吗?

恐怕这是不可能的——一种方法的rescue只能挽救其体内产生的错误。

处理此问题的一种方法是提供另一种在子类中覆盖的方法:

class Parent
# This is the public interface of the class, it is not supposed to be overriden
def execute!
perform
rescue => e
# do_sth_with_error
end
private
# Private implementation detail, override at will
def perform
end
end
class Child < Parent
private
def perform
raise "Something" if something?
# do some more things
super
end
end
Child.new.execute!

话虽如此 - 请不要拯救StandardError.这将使您未来的调试成为一场噩梦。请改为创建自己的错误子类。

你可以有这样的策略,但这取决于它应该如何工作以及你的代码是如何组织的。此模式可以扩展。对于您的特定情况,您可以按如下方式组织代码:

class Parent
def my_method(arg1, arg2)
yield if block_given?
# some code that should be run by Parent#my_method
rescue StandardError => e
# handle the error
end
end 
class Child < Parent
def my_method(arg1, arg2)
super do
# code that should be run by Child#my_method
raise StandardError.new('error message') if error?
# maybe more code that should be run by Child#my_method
end
end
def error?
true
end
end

使用此策略,您必须将方法中的所有代码作为块注入到父方法,通过唯一的语句super调用传递给父方法(嗯,基本上它是继承链中传递的闭包)。当然,此策略假设您的方法不使用块来实现其正常逻辑,您可以专门将此功能用于此执行注入。

如果你想使用此策略进行两个以上的继承级别,则必须对每个下一个方法使用相同的技巧

class C
def m1
yield if block_given?
# ...
rescue SomeError
# ...
end
end
class B < C
def m1
super do
yield if block_given?
# ...
end
end
end
class A < B
def m1
super do
raise SomeError if condition
# ...
end
end
end

如果应用此策略,您很可能可以删除if block_given?部分。

最新更新