gpt4 book ai didi

groovy - 在 Groovy 中覆盖元类属性

转载 作者:行者123 更新时间:2023-12-02 06:37:23 24 4
gpt4 key购买 nike

我想覆盖元类上的动态属性,但它没有按我的预期工作。这是一个演示该问题的简单示例。您可以在线运行它 Groovy web console

class Bike {}
class Bell { def ring() { println("calling " + this) } }

def createNamespaces = {
return [ "bell": new Bell() ]
}

def resetNamespaces = { bike ->
// setting to null means 'set it to the default'
bike.metaClass = null

createNamespaces().each { name, namespace ->
println("setting " + namespace)
bike.metaClass."$name" = namespace
}
}

def bike= new Bike()

resetNamespaces(bike)
bike.bell.ring()
resetNamespaces(bike)
bike.bell.ring()

结果是:

setting Bell@14e9bd2b
calling Bell@14e9bd2b
setting Bell@948a7ad
calling Bell@14e9bd2b

因此,尽管我更改了元类的属性,但调用它始终返回设置的第一个对象。有某种缓存吗?

当我将示例的最后一部分更改为:

resetNamespaces(bike)
resetNamespaces(bike)
bike.bell.ring()

那么结果就如预期了。也就是说,调用该属性会返回最后在元类上设置的对象:

setting Bell@5b47e0c7
setting Bell@19f373a4
calling Bell@19f373a4

我什至尝试按如下方式手动设置元类

def resetNamespaces = { bike ->
def newMetaClass = new ExpandoMetaClass(Bike.class, true, true)
newMetaClass.initialize()

bike.metaClass = newMetaClass

...
}

但是结果还是一样。所以必须涉及一些缓存机制。我在文档中找不到有关此行为的任何信息。

最佳答案

之所以会出现困惑,是因为您试图更改元类的属性,而不是方法。正如groovy metaprogramming官方文档中所述使用元类的 setAttribute/getAttribute 方法访问属性。

// throws MissingFieldException!
def resetNamespaces = { bike ->
createNamespaces().each { name, namespace ->
bike.metaClass.setAttribute(bike, name, namespace)
}
}

不幸的是,这只在该属性位于原始类定义中时才有效,这里它会抛出 MissingFieldException: No such field: bell for class: Bike

另一方面,覆盖方法就像一个魅力,并通过添加动态 getter 方法提供所需的语法:

def resetNamespaces(bike) {
createNamespaces().each { name, namespace ->
bike.metaClass."get${name.capitalize()}" = { namespace }
}
}

def bike = new Bike()
resetNamespaces(bike)
bike.bell.ring()
resetNamespaces(bike)
bike.bell.ring()

实际上,expando 也很好用

class Bell {
def ring() { println this }
}

def bike = new Expando()
bike.createNamespaces = {
return [ bell : new Bell() ]
}

bike.resetNamespaces = {
bike.createNamespaces().each { name, namespace ->
bike."$name" = namespace
}
}

bike.resetNamespaces bike
bike.bell.ring()
bike.resetNamespaces bike
bike.bell.ring()

关于groovy - 在 Groovy 中覆盖元类属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50745518/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com