首页 文章

Groovy c#表达式等效于评估属性

提问于
浏览
1

在.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(()=> 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

    我能提供最接近这种能力的感觉对我来说是完全做作的,而且是特别的 . 它依赖于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"
    

    YUK!

  • 0

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

    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就可以实现所有这一切的更加平滑的解决方案,它将您的属性或类的所有属性转换为"bound properties according to the JavaBeans spec" . 这会为您生成整个属性更改锅炉板代码,从而导致需要担心的代码更少 .

相关问题