我想动态地添加一个字段和方法到metaClass我当前的对象.我试过了
this.metaClass.testProp = "test"
Run Code Online (Sandbox Code Playgroud)
添加一个名为的字段testProp.但是,我明白了
groovy.lang.MissingPropertyException: No such property: testProp for class: groovy.lang.MetaClassImpl
Run Code Online (Sandbox Code Playgroud)
当我在类级别上执行相同操作时,例如将testProp添加到类而不是直接添加到对象
Process.metaClass.testProp = "test"
Run Code Online (Sandbox Code Playgroud)
它工作,但我的对象不继承该字段.我们将非常感谢任何正确方向的想法或指示.
简短回答:
Process.metaClass.testProp = "test"
this.metaClass = null
assert this.testProp == "test"
Run Code Online (Sandbox Code Playgroud)
答案很长:
我想,有三件事让你在这里遇到问题.第一个是meta类的全局注册表.第二个是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"
Run Code Online (Sandbox Code Playgroud)
如果您ExpandoMetaClass.enableGlobally()之前在某些设置代码中使用过,则可以保留元类的重置代码(或者如果全局元类与"this"相同,如果它是EMC).例如,Grails使用EMC作为默认值