当前位置: 首页 > 知识库问答 >
问题:

Ruby自定义错误类:消息属性的继承

黄俊智
2023-03-14

我似乎找不到有关自定义异常类的太多信息。

我所知道的

您可以声明您的自定义错误类并让它从Standard ardError继承,因此可以是拯救d:

class MyCustomError < StandardError
end

这允许您使用以下方法提升它:

raise MyCustomError, "A message"

稍后,在救援时获取该消息

rescue MyCustomError => e
  puts e.message # => "A message"

我不知道的是

我想给我的异常提供一些自定义字段,但我想从父类继承<code>消息@message不是exception类的实例变量,因此我担心我的继承将不起作用。

有人能告诉我更多细节吗?如何使用<code>对象

class MyCustomError < StandardError
  attr_reader :object
  def initialize(message, object)
    super(message)
    @object = object
  end
end

然后:

raise MyCustomError.new(anObject), "A message"

得到:

rescue MyCustomError => e
  puts e.message # => "A message"
  puts e.object # => anObject

它会起作用吗,如果它起作用,这是正确的做事方式吗?

共有3个答案

壤驷棋
2023-03-14

你的想法是对的,但你称呼它的方式是错的。应该是

raise MyCustomError.new(an_object, "A message")
平嘉熙
2023-03-14

鉴于 Exception 的 ruby 核心文档(所有其他错误都从中继承)声明了#message

返回调用exception.to_ s的结果。通常,这会返回异常的消息或名称。通过提供to_ str方法,异常同意在需要字符串的地方使用。

http://ruby-doc.org/core-1.9.3/Exception.html#method-i-message

我会选择将重新定义为_ s/为_str或初始值设定项。下面是一个示例,我们想以一种基本上人类可读的方式知道外部服务何时失败。

注意:下面的第二种策略使用 rails 漂亮的字符串方法,例如解调,这可能有点复杂,因此在异常情况下这样做可能是不明智的。如果需要,还可以向方法签名添加更多参数。

覆盖#to_s策略而不是#to_str,它的工作方式不同

module ExternalService

  class FailedCRUDError < ::StandardError
    def to_s
      'failed to crud with external service'
    end
  end

  class FailedToCreateError < FailedCRUDError; end
  class FailedToReadError < FailedCRUDError; end
  class FailedToUpdateError < FailedCRUDError; end
  class FailedToDeleteError < FailedCRUDError; end
end

控制台输出

begin; raise ExternalService::FailedToCreateError; rescue => e; e.message; end
# => "failed to crud with external service"

begin; raise ExternalService::FailedToCreateError, 'custom message'; rescue => e; e.message; end
# => "failed to crud with external service"

begin; raise ExternalService::FailedToCreateError.new('custom message'); rescue => e; e.message; end
# => "failed to crud with external service"

raise ExternalService::FailedToCreateError
# ExternalService::FailedToCreateError: failed to crud with external service

重写#初始化策略

这是我在rails中使用的最接近实现的策略。如上所述,它使用< code>demodualize 、< code >下划线和< code >人性化 < code > active support 方法。但这可以很容易地消除,就像在以前的策略中一样。

module ExternalService
  class FailedCRUDError < ::StandardError
    def initialize(service_model=nil)
      super("#{self.class.name.demodulize.underscore.humanize} using #{service_model.class}")
    end
  end

  class FailedToCreateError < FailedCRUDError; end
  class FailedToReadError < FailedCRUDError; end
  class FailedToUpdateError < FailedCRUDError; end
  class FailedToDeleteError < FailedCRUDError; end
end

控制台输出

begin; raise ExternalService::FailedToCreateError; rescue => e; e.message; end
# => "Failed to create error using NilClass"

begin; raise ExternalService::FailedToCreateError, Object.new; rescue => e; e.message; end
# => "Failed to create error using Object"

begin; raise ExternalService::FailedToCreateError.new(Object.new); rescue => e; e.message; end
# => "Failed to create error using Object"

raise ExternalService::FailedCRUDError
# ExternalService::FailedCRUDError: Failed crud error using NilClass

raise ExternalService::FailedCRUDError.new(Object.new)
# RuntimeError: ExternalService::FailedCRUDError using Object

演示工具

这是一个演示程序,展示了上述实现的救援和消息传递。引发异常的类是Cloudinary的一个假API。只需将上述策略之一转储到您的rails控制台中,然后执行以下操作。

require 'rails' # only needed for second strategy 

module ExternalService
  class FailedCRUDError < ::StandardError
    def initialize(service_model=nil)
      @service_model = service_model
      super("#{self.class.name.demodulize.underscore.humanize} using #{@service_model.class}")
    end
  end

  class FailedToCreateError < FailedCRUDError; end
  class FailedToReadError < FailedCRUDError; end
  class FailedToUpdateError < FailedCRUDError; end
  class FailedToDeleteError < FailedCRUDError; end
end

# Stub service representing 3rd party cloud storage
class Cloudinary

  def initialize(*error_args)
    @error_args = error_args.flatten
  end

  def create_read_update_or_delete
    begin
      try_and_fail
    rescue ExternalService::FailedCRUDError => e
      e.message
    end
  end

  private def try_and_fail
    raise *@error_args
  end
end

errors_map = [
  # Without an arg
  ExternalService::FailedCRUDError,
  ExternalService::FailedToCreateError,
  ExternalService::FailedToReadError,
  ExternalService::FailedToUpdateError,
  ExternalService::FailedToDeleteError,
  # Instantiated without an arg
  ExternalService::FailedCRUDError.new,
  ExternalService::FailedToCreateError.new,
  ExternalService::FailedToReadError.new,
  ExternalService::FailedToUpdateError.new,
  ExternalService::FailedToDeleteError.new,
  # With an arg
  [ExternalService::FailedCRUDError, Object.new],
  [ExternalService::FailedToCreateError, Object.new],
  [ExternalService::FailedToReadError, Object.new],
  [ExternalService::FailedToUpdateError, Object.new],
  [ExternalService::FailedToDeleteError, Object.new],
  # Instantiated with an arg
  ExternalService::FailedCRUDError.new(Object.new),
  ExternalService::FailedToCreateError.new(Object.new),
  ExternalService::FailedToReadError.new(Object.new),
  ExternalService::FailedToUpdateError.new(Object.new),
  ExternalService::FailedToDeleteError.new(Object.new),
].inject({}) do |errors, args|
  begin 
    errors.merge!( args => Cloudinary.new(args).create_read_update_or_delete)
  rescue => e
    binding.pry
  end
end

if defined?(pp) || require('pp')
  pp errors_map
else
  errors_map.each{ |set| puts set.inspect }
end
石苏燕
2023-03-14

raise已设置消息,因此您不必将其传递给构造函数:

class MyCustomError < StandardError
  attr_reader :object

  def initialize(object)
    @object = object
  end
end

begin
  raise MyCustomError.new("an object"), "a message"
rescue MyCustomError => e
  puts e.message # => "a message"
  puts e.object # => "an object"
end

我已将<code>救援异常,请查看为什么“救援异常”是一种糟糕的风格=

 类似资料:
  • 安全测试人员声称,我应该清理返回的JSON(即转义这些符号),因为这可能会给旧的浏览器带来一些问题(即在浏览器中执行此JS代码)。 但是生成错误消息的是SpringBoot框架, 我在这里没有太多的控制权。 当然,我可以将参数定义为String,并自己进行验证,但我怀疑这是否是正确的方法。我的参数定义为Integer,我希望它保持这种方式。 做这件事最简单的方法是什么?

  • 我用Python编写了一个类,这样就可以从中继承。它的逻辑按预期工作,但我可以从名为的派生类中存在的状态访问属性。 生成以下错误: state_machine.py main.py

  • 试图向OpenLDAP添加一个新属性,但总是碰壁。我正在尝试向架构添加ipPhone属性,因为我不能在默认的telephoneNumber属性中包含*数字。 下面是我的LDIF文件,用于创建新属性并将其与objectClass类似。 我已经测试和谷歌了几个小时,但一直无法解决这个问题或找出我错过了什么!

  • 您好,我正在使用CodeIgniter构建RESTAPIhttps://github.com/chriskacerguis/codeigniter-restserver/blob/master/application/libraries/REST_Controller.php. 在_detect_api_key()函数中,他只检查给定的Api Key是否与表中存储的密钥匹配。我修改了一点这个方法,

  • 我正在努力裁剪javax。验证。ConstraintValidator和javax。验证。根据我的需要限制ValidatorContext。我从格式错误的请求正文收到的响应消息始终采用以下形状: <代码> 此消息也以500而不是400错误请求的形式返回。我无法获得工作到解决方案来执行以下操作: 仅包括<代码> 我有以下代码: 向上面的代码发送格式错误的有效负载将导致如下消息: 我希望能够收到以下信

  • 我得到错误消息:未定义的属性: 我的控制器是 而我的模特是 而我的观点是 遇到PHP错误严重程度:注意 消息:未定义的属性:CI_DB_mysqli_result::num_row 文件名:models/Login\u mod。php 电话号码:27 回溯: 文件:C:\xampp\htdocs\ov400\application\models\Login\u mod。php行:27函数:\u错误