【问题标题】:Rescue on parent method an exception raised in child救援父方法引发子异常
【发布时间】:2021-12-19 19:49:25
【问题描述】:

在 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 在子方法中引发时,它将从父方法定义中解救出来。

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

【问题讨论】:

    标签: ruby exception inheritance rescue


    【解决方案1】:

    恐怕这是不可能的 - 一种方法的 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。它会让你未来的调试成为一场噩梦。改为创建您自己的错误子类。

    【讨论】:

    • 我认为这对我有用,谢谢!只是让你知道救援StandardError 只是一个例子:)
    【解决方案2】:

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

    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 调用(这是唯一的语句)将 子方法 中的所有代码作为传递给您父方法 的块注入(嗯,基本上它是在继承链中传递的一个闭包)。当然,这个策略假设你的方法不使用块来实现它的正常逻辑,你可以专门为这个执行注入使用这个特性。

    如果您想使用此策略获得两个以上的继承级别,则必须对每个 next 方法使用相同的技巧

    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? 部分。

    【讨论】:

    • 很高兴知道,我不知道这是可能的。我已经用rescue_from 解决了我的问题。但无论哪种方式都感谢:)
    • 好吧,那么您可能正在使用 Rails,并且有来自 ActionSupport 的 rescue_from,这有点超出了最初问题的范围,涉及 Ruby ...与正常继承。
    • 是的,这实际上是我的错。但我真的从你那里的回答中受益,我不知道这是可能的。非常感谢!
    猜你喜欢
    • 2021-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多