【问题标题】:Adding method to interface metaclass works only once向接口元类添加方法只工作一次
【发布时间】:2017-08-19 11:50:43
【问题描述】:

因此,将方法添加到接口元类会将其添加到接口实现的每个实例中——但只有一次。将方法添加到每个实现类每次都有效,以进行更改。

在重新分配方法之间清理元类似乎没有任何改变。

这是一个可运行的示例:

interface X {}
class A implements X {}
class B implements X {}

X.metaClass.test = { println "v1" }
new A().test()
new B().test()

X.metaClass.test = { println "v2" }
new A().test()
new B().test()

A.metaClass.test = { println "v3" }
B.metaClass.test = { println "v3" }

new A().test()
new B().test()

A.metaClass.test = { println "v4" }
B.metaClass.test = { println "v4" }

new A().test()
new B().test()

结果是:

v1
v1
v1
v1
v3
v3
v4
v4

这是预期的行为吗?如果是这样,那为什么?还是bug?

【问题讨论】:

  • 您期待v2 吗?在接口中,同一个方法可以声明多少次?一次对吗?
  • 预期输出;你的期望是什么?
  • 没错,我希望在X 接口上覆盖test 方法会调用它以使用被覆盖的行为——即打印“v2”字符串。对不起,但我真的不明白你的反问问题的明显性。当我像metaclass.someMethod 那样做某事时,我希望我不是真的两次声明相同的方法,而是覆盖之前的声明。有没有其他方法可以做到这一点?
  • 另外,如果执行“metaClass.someMethod”被解释为“两次声明相同的方法”而不是覆盖以前的实现(因为它似乎 is 在执行目标类上的相同内容)我希望有某种异常。

标签: groovy metaprogramming


【解决方案1】:

哇,我认为这实际上可能是一个长期存在的、未解决的错误 (GROOVY-3493)。看起来问题是,一旦在接口中声明了方法,就不能通过元类覆盖它。此限制不适用于类。

所以我的猜测是您第一次通过元类声明该方法时,它已正确初始化,因为它以前不存在。但是对接口 metaClass 方法的任何后续更新都不起作用,因为它已经存在。类 metaClass 更改有效,因为此错误不适用于它们。

工单中列出的解决方法似乎与您找到的解决方法相似;即,更新接口和类上的元类:

​interface X {}
class A implements X {} 
class B implements X {}  

X.metaClass.test = { println "v1" } 

new A().test() 
new B().test()  

X.metaClass.test = { println "v2" } 
A.metaClass.test = { println "v2" }

new A().test() // Will print "v2"
new B().test()​ // Will print "v1" still

【讨论】:

  • 哇,感谢您找到错误,我也寻找它但失败了。长期语言功能中的错误并不是一个理智的开发人员所期望的,所以很高兴知道确实如此,而不是我不了解它应该如何工作。然后... 8 年,很好!这个比#ProvidedGate issues.gradle.org/browse/GRADLE-784 更老练,但仍未解决!我将把赏金留几天,所以也许它会引起更多关注。
猜你喜欢
  • 2022-11-23
  • 1970-01-01
  • 1970-01-01
  • 2011-05-23
  • 2015-10-08
  • 1970-01-01
  • 1970-01-01
  • 2021-01-11
  • 1970-01-01
相关资源
最近更新 更多