删除/取消定义类方法

Posted

技术标签:

【中文标题】删除/取消定义类方法【英文标题】:Remove/undef a class method 【发布时间】:2011-01-05 23:02:12 【问题描述】:

您可以像这样为类动态定义类方法:

class Foo
end

bar = %qdef bar() "bar!" end
Foo.instance_eval(bar)

但是你如何做相反的事情:删除/取消定义一个类方法?我怀疑 Module 的 remove_methodundef_method 方法可能可以用于此目的,但我在谷歌搜索数小时后看到的所有示例都是用于删除/取消定义 instance 方法,不是类方法。或者,您也可以将一种语法传递给 instance_eval 来执行此操作。

提前致谢。

【问题讨论】:

【参考方案1】:
class Foo
  def self.bar
    puts "bar"
  end
end

Foo.bar    # => bar

class <<Foo
  undef_method :bar
end
# or
class Foo
  singleton_class.undef_method :bar
end

Foo.bar    # => undefined method `bar' for Foo:Class (NoMethodError)

当你定义一个像 Foo.bar 这样的类方法时,Ruby 把它放在 Foo 的单例类中。 Ruby 不能把它放在 Foo 中,因为那样它将是一个实例方法。 Ruby 创建 Foo 的单例类,将单例类的超类设置为 Foo 的超类,然后将 Foo 的超类设置为单例类:

Foo -------------> Foo(singleton class) -------------> Object
        super      def bar             super

有几种方法可以访问单例类:

class &lt;&lt;Foo, Foo.singleton_class, class Foo; class &lt;&lt; self,常用来定义类方法。

请注意,我们使用了undef_method,我们可以使用remove_method。前者阻止对该方法的任何调用,后者仅删除当前方法,如果存在则回退到超级方法。请参阅Module#undef_method 了解更多信息。

【讨论】:

我原以为不使用 Eigenclass 是可能的,至少在 1.9 中是这样。 @Andrew,也许是这样。唉,我不知道。 这在 Ruby1.9.3 中对我不起作用。我仍然能够调用删除的方法。 @joseph.hainline - 这很有趣!我刚刚确认上述方法在 MRI 1.8.3-p374、MRI 1.9.3-p484、MRI 2.0.0-p247 和 MRI 2.1.0 中有效。您是否正在做一些不同的事情,无论是在删除方法时,还是在调用它时,或者使用非 MRI Ruby 时? @joseph.hainline - 如果您在超类中有该方法,则该方法在您调用 remove_method 后仍然可以调用。你可以使用 undef_method 来阻止它。【参考方案2】:

这也适用于我(不确定 undef 和 remove_method 之间是否存在差异):

class Foo
end

Foo.instance_eval do
  def color
    "green"
  end
end

Foo.color # => "green"

Foo.instance_eval  undef :color 

Foo.color # => NoMethodError: undefined method `color' for Foo:Class

【讨论】:

这对我有用。我在一个对象上调用它,它只在对象级别删除它。 Foo.new.instance_eval undef :color 也可以。 removed_method 删除接收器类的方法,其中 undef_method 删除了继承类中的所有方法,包括接收器类。【参考方案3】:

您可以通过两种简单的方式删除方法。剧烈的

Module#undef_method( ) 

删除所有方法,包括继承的方法。善良的人

Module#remove_method( ) 

从接收器中删除方法,但它 保留继承的方法。

见下面2个简单的例子-

示例 1 使用 undef_method

class A 
    def x
        puts "x from A class"
    end
end

class B < A
    def x
        puts "x from B Class"
    end
    undef_method :x
end

obj = B.new
obj.x

结果 - main.rb:15:in ': undefined methodx' for # (NoMethodError)

使用 remove_method

的示例 2
class A 
    def x
        puts "x from A class"
    end
end

class B < A
    def x
        puts "x from B Class"
    end
    remove_method :x
end

obj = B.new
obj.x

结果 - $ruby main.rb

来自A类的x

【讨论】:

【参考方案4】:

我想我无法评论 Adrian 的回答,因为我没有足够的信誉,但他的回答帮助了我。

我发现:undef 似乎完全从存在中删除了该方法,而 remove_method 将其从该类中删除,但仍将在超类或已在此类上扩展的其他模块上定义,等等。

【讨论】:

在 Ruby 2.4 中它现在看起来是 undef_method【参考方案5】:

如果您想删除名称为动态计算的方法,您应该使用如下特征类:

class Foo
  def self.bar
    puts "bar"
  end
end

name_of_method_to_remove = :bar
eigenclass = class << Foo; self; end
eigenclass.class_eval do
  remove_method name_of_method_to_remove
end

这种方式比其他答案更好,因为这里我使用了带有块的 class_eval。由于您现在阻止查看当前命名空间,因此您可以使用变量来动态删除方法

【讨论】:

【参考方案6】:

Object.send(:remove_const, :Foo)

【讨论】:

这不是删除整个班级吗? 从技术上讲,这个答案并非不准确(即,事实上,这是一种删除类方法的方法),因为通过删除类 Foo 它也删除了 Foo 中的所有类方法:P:P: P。我的意思是,这显然不是 OP 真正想要的,但从技术上讲,它不是 false。其他技术上正确的答案:1)杀死包含的Ruby进程; 2) 重启操作系统; 3)把电脑扔进湖里; 4)在附近投下核弹; 5)触发超新星; 6)等待宇宙的热寂。

以上是关于删除/取消定义类方法的主要内容,如果未能解决你的问题,请参考以下文章

FutureFutureTask类解析

使用NS_UNAVAILABLE(不可用) NS_DESIGNATED_INITIALIZER(指定构造器) 关键自定义类的初始化方法

如何从另一个类中调用 onItemClick 方法?

为啥类定义的关键字参数在删除后会重新出现?

如何从 R 工作区中删除所有自定义方法和类?

EventBus事件通信框架 ( 订阅方法注册 | 注册 事件类型 - 订阅类 + 订阅方法 到指定集合 | 取消注册 数据准备 )