【问题标题】:Groovy dynamic property per object每个对象的 Groovy 动态属性
【发布时间】:2011-09-27 22:40:33
【问题描述】:

使用 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,我得到了“创建新属性”,但this.metaClass."$name" = "Dyna prop $name" 行失败:No such property: p1 for class at line 5

怎么了?

【问题讨论】:

    标签: dynamic groovy properties metaprogramming


    【解决方案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的标准示例

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

    【讨论】:

      【解决方案2】:

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

      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
      

      【讨论】:

        【解决方案3】:

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

        也许您想使用Runtime mixins。更多信息herehere

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

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

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

        【讨论】:

        猜你喜欢
        • 2013-03-25
        • 1970-01-01
        • 2020-10-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多