在.NET中,我们可以编写如下代码来返回属性Name
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(() => this.prop1) 它将返回属性名称。有关详细信息,请参阅此帖子(如何在不使用字符串名称的情况下引发 PropertyChanged 事件)
我想在时髦中做一些模拟的东西,但我不确定这样做的正确方法。
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 方法
我能最接近提供这种能力对我来说感觉完全是做作的、笨拙的和临时的。它依赖于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"
育!
对我来说,这种方法最有益的用途是在编译时,这样这种代码就会尽早中断,并且简单的字符串拼写错误不会在运行时导致错误。 在像groovy这样的高度动态的语言中,几乎没有办法获得适当的方法引用。 所以这里有一些代码,它在运行时执行此操作,但你唯一得到的就是一个断言(在下面的代码中),你正在控制。(clazz.&something
不是真正的方法引用,例如 Clazz::getSomething
在java8或C ++中)。 因此,这里有一些笨拙的尝试来滥用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'
也就是说,我在代码示例中看到的,在我看来,这整个技术可以帮助开发人员触发事件,以防止错误键入字符串的错误。 因此,通过使用 @Bindable
来解决这个问题,可能会有一个更时髦的解决方案,它将您的属性或类的所有属性转换为"根据 JavaBeans 规范的绑定属性"。 这将为您生成整个属性更改样板代码,从而减少需要担心的代码。