删除/取消定义类方法
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_method
和 undef_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 <<Foo
,
Foo.singleton_class
,
class Foo; class << 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 method
x' for # (NoMethodError)
使用 remove_method
的示例 2class 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)等待宇宙的热寂。以上是关于删除/取消定义类方法的主要内容,如果未能解决你的问题,请参考以下文章
使用NS_UNAVAILABLE(不可用) NS_DESIGNATED_INITIALIZER(指定构造器) 关键自定义类的初始化方法
EventBus事件通信框架 ( 订阅方法注册 | 注册 事件类型 - 订阅类 + 订阅方法 到指定集合 | 取消注册 数据准备 )