Groovy Expando Metaclass setter访问

时间:2017-08-10 19:04:26

标签: groovy

我使用虚拟Employee groovy类编写了以下测试。

@Test
void returnPropertyIfPropertyIsAvailableOnMetaClass(){
    def emp=new Employee()
    emp.metaClass.sayGutenAbend="Guten Abend"
    assert emp.sayGutenAbend=="Guten Abend"
    assert emp.sayGutenAbend==emp.metaClass.getProperty(emp,"sayGutenAbend")
    emp.metaClass.setProperty(emp,"sayGutenAbend","Guten Morgen")
    assert emp.sayGutenAbend=="Guten Morgen"
    assert emp.sayGutenAbend==emp.metaClass.getProperty(emp,"sayGutenAbend");
}

以下测试通过,而以下失败 -

@Test
void returnPropertyIfPropertyIsAvailableOnMetaClass_Fails(){
    def emp=new Employee()
    emp.metaClass.sayGutenAbend="Guten Abend"
    assert emp.sayGutenAbend=="Guten Abend"
    assert emp.sayGutenAbend==emp.metaClass.getProperty(emp,"sayGutenAbend")
    emp.metaClass.sayGutenAbend="Guten Morgen"
    assert emp.sayGutenAbend=="Guten Morgen"
    assert emp.sayGutenAbend==emp.metaClass.getProperty(emp,"sayGutenAbend")
}

与前一代码示例的唯一区别是,在元类上为同一属性设置新值。只是好奇。谁能指出我为什么这样做?

1 个答案:

答案 0 :(得分:1)

使用元编程创建字段后,您无需使用metaClass重置字段:

class Employee{}

def emp = new Employee()

emp.metaClass.sayGutenAbend="Guten Abend"
assert emp.sayGutenAbend=="Guten Abend"
assert emp.sayGutenAbend==emp.metaClass.getProperty(emp,"sayGutenAbend")

emp.sayGutenAbend="Guten Nacht"
assert emp.sayGutenAbend=="Guten Nacht"
assert emp.sayGutenAbend==emp.metaClass.getProperty(emp,"sayGutenAbend")

我猜测这种情况是由于重新创建了元类的某些部分而发生的,而您想要的是将绑定的对象实例更改为对象实例。 This answer可能是相关的。

在此代码段中,重置属性会创建一个新的ThreadManagedMetaBeanProperty,因此会失败:

class Employee{}

def emp = new Employee()
emp.metaClass.sayGutenAbend="Guten Abend"

def metaclass1 = emp.metaClass.properties[1]
emp.metaClass.sayGutenAbend="Guten Nacht"

def metaclass2 = emp.metaClass.properties[1]

assert metaclass1 == metaclass2 // fails

虽然这有效:

class Employee{}

def emp = new Employee()
emp.metaClass.sayGutenAbend="Guten Abend"

def metaclass1 = emp.metaClass.properties[1]
emp.sayGutenAbend="Guten Nacht"

def metaclass2 = emp.metaClass.properties[1]

assert metaclass1 == metaclass2 // works