簡體   English   中英

Kotlin:引用已知時確定屬性名稱

[英]Kotlin: determine property name when reference is known

假設我們有兩個類 A 和 B。框架將要求 A 具有 0 個或多個 B 類型的屬性。用戶可以引用 B 的實例。為簡單起見,假設只能聲明類型 B class A 內。

class A {

    private val myFirstB = B(this)
    private val mySecondB = B(this)

    val listOfB: List<B> = mutableListOf(myFirstB, mySecondB)
    
}

class B(a: A) {
    val myA : A = a
    fun doSomething(){
        // great stuff
    }
}

fun testIt(){
    val a = A()
    val b1 = a.listOfB[0]
}

通過 Kotlin 反射,當我們只有引用 b1 時,如何確定 A 中持有對 b1 引用的屬性的名稱。 我們還知道 B 有一個對 A 的引用。通過實例 B,我們可以獲得 A 的實例。使用反射,我們可以通過 declaredMemberProperties 屬性獲取 A 的屬性。 這可以迭代以獲取所有屬性的名稱。 但是,我不明白如何確保檢索到的名稱與引用 b1 相關聯。

正如評論中所說,您的案例看起來非常具體,通常反射對於此類案例並不理想。 該算法要么必須針對這種非常特殊的情況,包括b1始終在列表中的事實。 或者它必須支持許多不同的情況並“猜測”在哪里尋找b1

基本上,想法是獲取每個成員的值並將其與搜索值進行比較:

fun main() {
    val a = A()
    val b1 = a.listOfB[0]

    // prints: "listOfB"
    println(findPropertyNameByValue(a, b1))
}

fun findPropertyNameByValue(owner: Any, value: Any): String {
    return owner::class.memberProperties.first { prop ->
        @Suppress("UNCHECKED_CAST")
        val list = (prop as KProperty1<Any, *>).get(owner)
        list is List<*> && list.any { it === value }
    }.name
}

我們甚至可以單獨從b1中獲取“listOfB”,然后算法將不得不遍歷成員兩次,再次猜測值是否是我們A 但這在技術上是可行的。

經過一些試驗后,getter 調用保存了所需的引用。 這是一些可能的代碼:

import kotlin.reflect.KClass
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.KProperty1

fun main(){
    val a = A()
    val b1 = a.listOfB[0]
    println(b1)
    val clz: KClass<out A> = a::class
    val properties: Collection<KProperty1<out A, *>> = clz.declaredMemberProperties
    for(p in properties){
        println(p)
        println(p.name)
        println(p.getter.call(a))
        if (p.getter.call(a)?.equals(b1) == true){
            println("This is b1")
        }
    }
}

class A {

    val myFirstB = B(this)
    val mySecondB = B(this)

    val listOfB: List<B> = mutableListOf(myFirstB, mySecondB)

}
var cnt = 1
class B(a: A) {
    val myA : A = a
    val s = cnt++
    fun doSomething(){
        // great stuff
    }
}

這具有以下 output:

ksl.B@4590c9c3
val ksl.A.listOfB: kotlin.collections.List<ksl.B>
listOfB
[ksl.B@4590c9c3, ksl.B@d62fe5b]
val ksl.A.myFirstB: ksl.B
myFirstB
ksl.B@4590c9c3
This is b1
val ksl.A.mySecondB: ksl.B
mySecondB
ksl.B@d62fe5b

可以看出,getter 是否報告它正確找到 b1 的測試

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM