2

让我们考虑一个简单的 Groovy DSL

execute {
    sendNotification owner
    sendNotification payee
}

执行的实现是

public static void execute(Closure dslCode) {
    Closure clonedCode = dslCode.clone()
    def dslDelegate = new MyDslDelegate(owner:  'IncCorp', payee: 'TheBoss')

    clonedCode.delegate = dslDelegate
    clonedCode.call()
}

和自定义代表是

public static class MyDslDelegate {
    def owner
    def payee

    void sendNotification(to) {
        println "Notification sent to $to"
    }
}

execute运行块的预期结果是

Notification sent to IncCorp
Notification sent to TheBoss

实际的是

Notification sent to class package.OwnerClassName
Notification sent to TheBoss

问题是ownerGroovy 本身的保留属性,由于 Groovy实现Closure,没有resolveStrategy选项有助于owner用委托的自定义值替换值getPropertyClosure

public Object getProperty(final String property) {
    if ("delegate".equals(property)) {
        return getDelegate();
    } else if ("owner".equals(property)) {
        return getOwner();
    ...
    } else {
        switch(resolveStrategy) {
            case DELEGATE_FIRST:
        ...
    }

我的问题是,有人如何能够产生这种限制并owner在自定义 DSL 中使用属性名称?

4

2 回答 2

1

这有点小技巧,但这应该可以得到你想要的,而不改变 Groovy 源代码:

public static void execute(Closure dslCode) {
    Closure clonedCode = dslCode.clone()

    def dslDelegate = new MyDslDelegate(owner:  'IncCorp', payee: 'TheBoss')
    clonedCode.@owner = dslDelegate.owner
    clonedCode.resolveStrategy = Closure.DELEGATE_ONLY

    clonedCode.delegate = dslDelegate
    clonedCode.call()
}

参考: 是否可以更改闭包的所有者?

于 2012-11-02T23:53:47.253 回答
1

简单的答案是否定的,你不能。'owner' 是 Groovy 中的保留关键字,因此根据定义不能用作任意符号。即使有办法解决这个问题,你最好只使用一个与语言实现不冲突的名称——这在 Groovy 中尤其如此,它一直承诺完全重新设计其 MOP,这意味着您实施的任何 hack 都可能在未来的版本中停止工作。

如果您解释了为什么您愿意提供赏金并寻找解决此问题的方法,而不是仅仅将名称更改为不同的名称并完全避免该问题,那么这个问题可能会更有意义。保留符号是一种语言的一个非常基本的限制,试图绕过它们似乎是非常不明智的。

于 2012-11-05T01:29:07.570 回答