首页 文章

每个对象的Groovy动态属性

提问于
浏览
5

使用Groovy 1.8 . 我正在尝试创建一个动态类定义,它将缓存每个对象的属性 . 我没有使用 propertyMissing 而没有将属性添加到对象就好了 . 我只是认为缓存属性会更有效率 . 对?

请注意,每个实例必须具有自己的不同属性 .

以下代码工作正常:

class C {}
def c = new C()
c.metaClass.prop = "a C property"
println c.prop

def x = new C()
x.prop

将输出:

a C property
groovy.lang.MissingPropertyException: No such property: prop for class: C

如果我需要这个问题:

class A {
    def propertyMissing(String name) {
        if(!this.hasProperty(name)) {
            println "create new propery $name"
            this.metaClass."$name" = "Dyna prop $name"
            println "created new propery $name"
        }
        this.metaClass."$name"
    }
}

a = new A()
println a.p1

对于 A ,我得到了"create new property",但是 this.metaClass."$name" = "Dyna prop $name" 行失败了: No such property: p1 for class at line 5

怎么了?

3 回答

  • 1

    为什么不将动态属性存储在简单的HashMap中?

    class Foo {
        def storage = [:]
        def propertyMissing(String name, value) { storage[name] = value }
        def propertyMissing(String name) { storage[name] }
    }
    def f = new Foo()
    f.foo = "bar"
    

    这是标准示例:http://groovy.codehaus.org/Using+methodMissing+and+propertyMissing

    注意,您不必检查属性是否真的丢失...如果它不会丢失,则首先不会调用该方法 .

  • 6

    这段代码应该做你想要的:

    class A {
      A() {
        def mc = new ExpandoMetaClass( A, false, true)
        mc.initialize()
        this.metaClass = mc
      }
    
      def propertyMissing( String name ) {
        println "create new propery $name"
        def result = "Dyna prop $name"
        this.metaClass."$name" = result
        println "created new propery $name"
        result
      }
    }
    
    a = new A()
    println a.p1
    println a.p1
    

    那输出:

    create new propery p1
    created new propery p1
    Dyna prop p1
    Dyna prop p1
    
  • 8

    ExpandoMetaClass并非真正设计为在初始化或实例变量之后使用(请参阅下面的参考,至少为1.6或更早版本) .

    也许你想使用Runtime mixins . 更多信息herehere .

    您可能希望阅读blogpost,提供了一种解决方法来在运行时定义属性 . 与之相关的groovy bug(这不是一个真正的错误) .

    我在评论部分看到并至少在版本1.6 ExpandoMetaClass文档中进行了验证:

    默认情况下,只允许在调用initialize()之前添加方法 . 换句话说,您创建一个新的ExpandoMetaClass,添加一些方法,然后调用initialize() . 如果在调用initialize()之后尝试添加新方法,则将抛出错误 .

相关问题