2016-10-16 57 views
3

在科特林,您可以使用引用操作符来获得KProperty包扩展属性是这样的:获取非包扩展属性的KProperty

val String.extProp: String 
    get() = "Some get code" 

fun foo() { 
    val prop: KProperty<String> = String::extProp 
} 

然而,当扩展特性内宣布类参考操作不再起作用:

class Example() { 

    val String.extProp: String 
     get() = "Some get code" 

    fun foo() { 
     val prop: KProperty<String> = String::extProp // error 
    } 

} 

因此,我想知道我是如何改变在第二个例子中有问题的线路,所以KProperty是得到?

回答

5

你所得到的错误是:

Error:(y, x) Kotlin: 'extProp' is a member and an extension at the same time. References to such elements are not allowed

没有语法机制来生成到一个扩展方法,该方法还需要一种含类的引用。例如,你的扩展可能会使用该类的成员,这需要像Kotlin 1.1中的“bound references”(我不确定是否会覆盖这种情况,它目前是open question)。所以现在,有没有::语法可用。像Example::String::extProp这样的东西是不是可用,也不是通常尝试的Example::String.extProp语法。但你可以通过反思找到它。

首先你要知道你将收到的类型是:

KProperty2<INSTANCE, EXTENDING, PROPTYPE> 

而上一类正常的属性是:

KProperty1<INSTANCE, PROPTYPE> 

你需要知道,因为任何呼叫getter将需要类实例和属性正在扩展的类的实例。所以你不能像调用一个类的属性引用那样调用它。

您可以使用此功能来查找一个类中声明的扩展属性:

@Suppress("UNCHECKED_CAST") 
fun <T: Any, EXTENDING: Any, R: Any> KClass<T>.extProp(extends: KClass<EXTENDING>, name: String, returning: KClass<R>): KProperty2<T, EXTENDING, R> { 
    return this.declaredMemberExtensionProperties.first { 
     it.name == name && 
       it.parameters.size == 2 && 
       it.parameters[0].kind == KParameter.Kind.INSTANCE && it.parameters[0].type == this.defaultType && 
       it.parameters[1].kind == KParameter.Kind.EXTENSION_RECEIVER && it.parameters[1].type == extends.defaultType && 
       it.returnType == returning.defaultType 
    } as KProperty2<T, EXTENDING, R> 
} 

这是检查有点大材小用,但确保它是面向未来的情况下,任何其他类型的扩展名是稍后添加。以下是您的代码更新使用它:

class Example() { 
    val String.extProp: String 
     get() = "howdy $this" 

    fun foo() { 
     val prop = Example::class.extProp(String::class, "extProp", String::class) 
     println(prop.get(this, "stringy")) // "howdy stringy" 
    } 
}