如何通过反射运行挂起方法?

Art*_*nov 2 java coroutine async-await kotlin kotlin-coroutines

有一个可以运行挂起功能的协程块.

但是我invoke通过反射来调用函数.这是java风格的调用,显然简单的调用是行不通的.有没有办法异步运行反射方法?如何等待这种方法?

import kotlin.coroutines.experimental.*

class TestClass(val InString: String) {
    suspend fun printString() {
        println(InString)
    }
}

fun launch(context: CoroutineContext, block: suspend () -> Unit) =
        block.startCoroutine(StandaloneCoroutine(context))

private class StandaloneCoroutine(override val context: CoroutineContext): Continuation<Unit> {
    override fun resume(value: Unit) {}

    override fun resumeWithException(exception: Throwable) {
        val currentThread = Thread.currentThread()
        currentThread.uncaughtExceptionHandler.uncaughtException(currentThread, exception)
    }
}

fun main(args: Array<String>) {
    launch(EmptyCoroutineContext) {
        val a = TestClass("TestString");

        for (method in a.javaClass.methods) {
            if (method.name == "printString")
                method.invoke(a)  // Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments 

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Rom*_*rov 9

更新

由于Kotlin 1.3反射本身支持通过KFunction.callSuspend和调用挂起函数KFunction.callSuspendBy,因此不再需要上述解决方法.

原始答案

suspendKotlin中的每个方法都通过CPS转换在JVM上表示,这在协程设计文档中有解释.Java反射不知道它,Kotlin反射目前也没有提供执行挂起函数调用的方便手段.

您必须通过辅助函数自行调用CPS转换.我建议为此目的实现以下帮助器:

import java.lang.reflect.Method
import kotlin.coroutines.experimental.intrinsics.*

suspend fun Method.invokeSuspend(obj: Any, vararg args: Any?): Any? =
    suspendCoroutineOrReturn { cont ->
        invoke(obj, *args, cont)
    }
Run Code Online (Sandbox Code Playgroud)

现在,如果你更换invoke使用invokeSuspend在你的代码,然后它会如同预期工作.