2015-09-05 43 views
4

我想动态地将字段和方法添加到当前对象的metaClass。我试过Groovy - 将属性或方法动态添加到此类的metaClass中

this.metaClass.testProp = "test" 

要添加一个名为testProp的字段。但是,我得到

groovy.lang.MissingPropertyException: No such property: testProp for class: groovy.lang.MetaClassImpl 

当我在班级上做同样的事情时,加入testProp到类,而不是直接向对象

Process.metaClass.testProp = "test" 

它的工作原理,但我的目标继承领域。任何想法或指针在正确的方向将不胜感激。

回答

6

简短的回答:

Process.metaClass.testProp = "test" 
this.metaClass = null 
assert this.testProp == "test" 

龙答:

我认为,有三件事情,在这里让你一个问题。第一个是有一个全局的元类注册表。第二个是Groovy允许每个实例元类(这是Groovy类的默认值)。第三个是默认的元类不允许运行时元编程。

因此,如果您运行时元编程,会发生什么情况,因此默认需要由ExpandoMetaClass(EMC)取代以允许执行此操作。但是由于每个实例都有一个元类逻辑,所以此替换可能不会影响所有实例。首次使用该实例的元类时,它将从全局注册表中获取。 Process.metaClass.testProp = "test"更改全局保存的一个。任何已经有元类的实例都不会知道更改,因此不知道属性。 this.metaClass.testProp = "test"只会改变当前实例的元类,其他实例可能不知道它。您可以使用this.metaclass = null来重置它。它会再次从全局注册表中请求元类。如果您执行了每个实例的更改,则您的更改将消失。如果你做了全球变化,你的变化现在已经可见了。

如果您使用Groovy中的默认元类(MetaClassImpl),所有这一切都很重要。如果您在代码中进行更改,则新的元类将为ExpandoMetaClass(EMC)。这个元类允许进行更改,所以进一步的更改不会导致元类的替换。为了确保所有情况下采取从一开始的ExpandoMetaClass你通常有一些像这样的设置代码:ExpandoMetaClass.enableGlobally()

所以要解决你的问题,我可以简单地这样做

Process.metaClass.testProp = "test" 
this.metaClass = null 
assert this.testProp == "test" 

如果你在一些设置中使用ExpandoMetaClass.enableGlobally()代码之前,可以将元类的重置代码退出(或者,如果全局元类与“this”的元类相同,并且它是EMC)。 Grails例如使用EMC作为默认值

相关问题