计算属性的Groovy c#表达式等价

计算属性的Groovy c#表达式等价,groovy,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;

在.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; }
 }

您将如何在groovy中使用如上所示的表达式实现getName方法?我认为最接近于提供此功能的方法完全是人为的、笨拙的、临时的。它依赖于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"

哎呀

对我来说,这种方法最有益的用途是在编译时使用,这样这种代码就可以尽早中断,并且简单的字符串输入错误不会在运行时导致bug。在像groovy这样的高度动态的语言中,很难找到合适的方法引用来使用。下面是一些代码,它在运行时执行此操作,但是您从中得到的唯一东西是您正在控制的断言(在下面的代码中)。(
clazz.&something
不是您在java8或c++中使用的真正方法引用,例如
clazz::getSomething
)。因此,这里有一些笨拙的尝试,试图滥用
MethodClosure
,并做一个简单的检查,如果所属类在运行时有此的getter

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'

也就是说,我在代码示例中看到的是,在我看来,整个技术似乎可以帮助开发人员触发事件,以防止错误输入字符串。因此,可能有一个更为groovyier的解决方案来解决所有这些问题,只需使用,它将您的属性或类的所有属性转换为“根据JavaBeans规范绑定的属性”。这会为您生成整个属性更改模板代码,从而减少需要担心的代码。

这是一个拦截器吗?如果有方法
Clazz.getwhere(字符串内容)
,则使用这种方法可能会得到误报。在这种情况下,该方法接受一个参数,因此不表示属性。但是,
assert getName(c.&whater)==“whater”
仍然通过。可能在
getName()
方法中有一个附加的断言,比如
assert.parameterTypes.size()==0
order@BalRog是的,如果有什么东西,也可以检查所有者/委托的属性,这可能更容易,但需要一个find{}True dat。这里还有一个可能的bug。我还没有确定检查过,但是我认为如果属性名是单个字符,子表达式
${m[1..-1]}
将抛出某种“索引超出范围”异常。过去我不得不使用一些笨拙的东西,比如
${m[1..@BalRog,简而言之:as yuk as;)
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'