Groovy c#表达式等同于evaluate属性

时间:2014-11-15 00:18:31

标签: groovy

在.NET中,我们可以编写如下代码来返回propertyName

public static string GetName(Expression<Func<object>> exp)
{
    MemberExpression body = exp.Body as MemberExpression;

    if (body == null) {
        UnaryExpression ubody = (UnaryExpression)exp.Body;
        body = ubody.Operand as MemberExpression;
    }

     return body.Member.Name;
 }

 public class Test
 {
     public string prop1 { get; set; }
 }

在属性内部,我们通常使用OnPropertyChanged(()=&gt; this.prop1)来返回propertyName。有关详细信息,请参阅此帖子(How to raise PropertyChanged event without using string name

我想在groovy中做一些类似的事情,但我不确定这样做的正确方法。

    class TestObj
    {
        def prop1 = "value" 
        def prop2 = "value"
    }

    class Test{
        def something(){
            def t1 = new TestObj()
            def propertyName1 = getName{ t1.prop1 }
            def propertyName2 = getName{ t1.prop2 }

            assert propertyName1 == "prop1"
            assert propertyName2 == "prop2"
        }
    }

如何使用如上所示的表达式在groovy中实现getName方法

2 个答案:

答案 0 :(得分:0)

我能提供最接近这种能力的感觉对我来说感觉完全是人为的,而且非常狡猾,并且 ad hoc 。它依赖于Java Bean API,由Groovy @Vetoable注释提供便利,以保持之外的大部分丑陋类代码:

import groovy.beans.Vetoable

import java.beans.PropertyChangeEvent
import java.beans.PropertyVetoException

class TestObj {
    @Vetoable def prop1 = "value"
    @Vetoable def prop2 = "value"
}

def t1 = new TestObj()
def getName(def t, Closure c) {
    def name
    t.vetoableChange = { PropertyChangeEvent pce ->
        if (!pce.newValue) { throw new PropertyVetoException("", pce) }
    }
    try { c.call() }
    catch (PropertyVetoException e) { name = e.propertyChangeEvent.propertyName }
    t.vetoableChange = { it -> }
    name
}
def propertyName1 = getName(t1) { t1.prop1 = null }
def propertyName2 = getName(t1) { t1.prop2 = null }

assert propertyName1 == "prop1"
assert propertyName2 == "prop2"

议员!

答案 1 :(得分:0)

对我来说,这种方法的最有益的用途是编译时,所以这种代码尽可能早地破解,简单的字符串错误不会导致运行时的错误。在像groovy这样高度动态的语言中,几乎没有办法获得适当的方法引用。所以这里有一些代码,它在运行时执行,但是你唯一能得到的就是你正在控制的断言(在下面的代码中)。 (clazz.&something不是一个真正的方法引用,就像你在java8或c ++中得到的Clazz::getSomething一样。所以,如果拥有的类在运行时拥有一个getter ,那么这里有一些笨拙的尝试滥用MethodClosure并做一个简单的检查。

class Clazz {
    String username
    String firstName
    def lastName
    String getFake() { return 'fake' }
    void setSomething(String something) {}
}

String getName(org.codehaus.groovy.runtime.MethodClosure it) { 
    def m = it.method.toString()
    assert it.delegate.respondsTo("get${m[0].toUpperCase()}${m[1..-1]}")
    it.method.toString()
}

def c = new Clazz()
assert getName(c.&username) == 'username'
assert getName(c.&lastName) == 'lastName'
assert getName(c.&fake) == 'fake'

那就是说,我在代码示例中看到的,这整个技术在我看来是帮助开发人员在触发事件方面来防止错误输入字符串的错误。因此,通过使用@Bindable可能会有一个更加平滑的解决方案,它会根据JavaBeans规范将您的属性或类的所有属性转换为绑定属性&#34;。这会为您生成整个属性更改锅炉板代码,从而导致需要担心的代码更少。