Как собрать членов с помощью отражения, чтобы передать в качестве аргумента позже - PullRequest
0 голосов
/ 01 мая 2018

Итак, я работаю над концепцией, которая предполагает автоматическую запись в ByteBuffer содержимого класса, расширяющего Bufferizable

abstract class Bufferizable {

    abstract val fieldOrder: Array<String>

    open fun size(): Int = TODO()

    var initialized = false

    open infix fun to(address: Long) {

        if (initialized) {

            addFunctions.forEach {  }

        } else {

            addFunctions = Array(fieldOrder.size) { null }
            members = Array(fieldOrder.size) { null }

            fieldOrder.forEachIndexed { i, field ->
                val member = this::class.declaredMemberProperties.find { it.name == field }!!
                addFunctions[i] = when (member.returnType) {
                    Mat4::class.defaultType.javaType -> WithAddress::addMat4
                    ...
                    else -> throw Error()
                } as BufferizableAddFunctionType
                members[i] = member.get(this) // error
            }

            initialized = true
        }
    }

    infix fun from(address: Long): Unit = TODO()

    var addFunctions = arrayOf<BufferizableAddFunctionType?>()
    var members = arrayOf<Any?>()
}

typealias BufferizableAddFunctionType = (Any) -> Unit

object WithAddress {

    var address = NULL
    var offset = 0

    fun addMat4(mat4: Mat4) {
        for (i in 0..3)
            for (j in 0..3) {
                memPutFloat(address + offset, mat4[i, j])
                offset += Float.BYTES
            }
    }
    ...
}

Идея состоит в том, чтобы объявить, например, следующее

object uboVS : Bufferizable() {

    var projectionMatrix = Mat4()
    var modelMatrix = Mat4()
    ...

    override val fieldOrder = arrayOf("projectionMatrix", "modelMatrix", "viewMatrix")
}

И затем всякий раз, когда uboVS to address будет вызван в первый раз, он будет инициализирован, а затем его содержимое будет записано по собственному адресу в указанном порядке.

Но единственная проблема, с которой я застрял, - это сбор членов для передачи в качестве аргумента i-й addFunction

потому что компилятор жалуется здесь:

members[i] = member.get(this)

Ошибка: (328, 37) Котлин: Запроектированный тип 'KProperty1' запрещает использование 'public abstract fun get (получатель: T): R определен в kotlin.reflect.KProperty1'

Как я могу решить?

1 Ответ

0 голосов
/ 01 мая 2018

Это проблема наследования. Ваш рефлексивный вызов this::class.declaredMemberProperties.find{ ... } возвращает KProperty1<out Bufferizable, Any?> Это означает, что свойство от чего-то, что унаследовано от Bufferizable (см. объявление-отклонение сайта для получения дополнительной информации о out). Через копилер не знает, к какому классу принадлежит это свойство, он не разрешает прямой доступ. Чтобы решить эту проблему, вы должны получить доступ к функции получения:

members[i] = member.getter.call(this)

Через функцию получения принадлежит объекту, а не к API-интерфейсу отражения, она следует поведению наследования по умолчанию и может вызываться.

...