2016-09-10 41 views
3

如何獲取成員屬性的委託類?Kotlin:我怎樣才能獲得成員資產的授權類?

這樣,我的意思是有可能完成這樣的功能:

inline fun <reified T> delegationExample(t: T) { 
    for (prop in T::class.declaredMemberProperties) { 
     val delegatedClass = // what to do?! 
    } 
} 

凡委託類可能看起來像:

class DelegationExample { 
    operator fun getValue(ref: Any, prop: KProperty<*>) = 0 
} 

的報關類可能是這樣的:

object Example { 
    val a by DelegationExample() 
    val b by DelegationExample() 
    val c by DelegationExample() 
} 

回答

3

要查找委託給委託類與類的實例一起性質,這裏是一個效用函數:

data class DelegatedProperty<T : Any, DELEGATE : Any>(val property: KProperty1<T, *>, val delegatingToInstance: DELEGATE) 

inline fun <reified T : Any, DELEGATE : Any> findDelegatingPropertyInstances(instance: T, delegatingTo: KClass<DELEGATE>): List<DelegatedProperty<T, DELEGATE>> { 
    return T::class.declaredMemberProperties.map { prop -> 
     val javaField = prop.javaField 
     if (javaField != null && delegatingTo.java.isAssignableFrom(javaField.type)) { 
      javaField.isAccessible = true // is private, have to open that up 
      @Suppress("UNCHECKED_CAST") 
      val delegateInstance = javaField.get(instance) as DELEGATE 
      DelegatedProperty(prop, delegateInstance) 
     } else { 
      null 
     } 
    }.filterNotNull() 
} 

的幾個注意事項:

  • 首先糾正你的具體化鍵入TT: Any或者您無法訪問Kotlin反射中的所有擴展名,包括declaredMemberProperties
  • 從屬性參考到現場最容易,以確保你實際上在談論某個屬性,因此每個declaredMemberProperties使用​​來做到這一點。
  • 由於​​是一個自定義getter,可以爲空,它被保存到一個局部變量,所以智能鑄造將在以後工作。
  • 然後,如果此字段的類型與您正在查找的代理類相同,則可以訪問該字段。
  • 但首先你必須強制該字段的可訪問性,因爲它是一個private字段。

測試程序運行以下命令:

class DelegationExample { 
    operator fun getValue(ref: Any, prop: KProperty<*>) = 0 
} 

class Example { 
    val a by DelegationExample() 
    val b by DelegationExample() 
    val c by DelegationExample() 
} 

fun main(args: Array<String>) { 
    findDelegatingPropertyInstances(Example(), DelegationExample::class).forEach { 
     println("property '${it.property.name}' delegates to instance of [${it.delegatingToInstance}]") 
    } 
} 

的輸出是一樣的東西:

property 'a' delegates to instance of [[email protected]] 
property 'b' delegates to instance of [[email protected]] 
property 'c' delegates to instance of [[email protected]] 
+0

我的補丁:https://gist.github.com/Jire/df9c99fac5e4d3f35e1a6c517716f989 – Jire

+1

當然,都做類似的事情。我想在這個例子中返回委託的所有東西,並且不會在任何我不需要的地方調用'isAccessible'(在調用它的時候會有影響嗎?) –

+0

您引用的補丁(Jire)只會在只是一個聲明的屬性,它使用作爲第二個參數傳遞的委託。無論如何,當有兩個或更多屬性使用相同的代理時,爲給定屬性找到代表?我很想有一個可以做到這一點的功能。我試圖弄清楚,但我不認爲這是可能的。 –

1

關於字節代碼級委託屬性不推遲從常規(publi c getter/setter和一個私人字段)。

你可以去的一種方法是掃描Example的私人字段並過濾那些有operator getValue(thisRef: R, KProperty<*>)的字段。從技術上講,一個字段可能包含代理對象val x = lazy {1},但這不太可能。