有一个可以运行挂起函数的协程块。
但我通过反射调用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
}
}
}
答案 0 :(得分:9)
<强>更新强>
由于Kotlin 1.3反射本身支持通过KFunction.callSuspend
和KFunction.callSuspendBy
调用暂停功能,因此不再需要上述解决方法。
原始答案
Kotlin中的每个suspend
方法都通过CPS转换在JVM上表示,coroutines design document中对此进行了解释。 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)
}
现在,如果您在代码中将invoke
替换为invokeSuspend
,那么它就会像预期的那样工作。