Kotlin中如何优雅地用Method.invoke()动态调用不同参数的方法
问题分析
你遇到的报错本质是Kotlin函数引用的类型擦除与反射invoke的类型不兼容:当你把Function3(对应concatenation)和Function2(对应subtraction)放进同一个List时,它们会被统一推断为KFunction<*>类型,编译器无法确定参数是否匹配,运行时也会因类型不匹配抛出异常。
下面是几种优雅的解决方案,按推荐优先级排序:
方案一:Lambda直接封装(最简洁、类型安全)
直接把每个方法调用包装成无参Lambda,完全避免反射,编译期就能检查参数正确性,代码清晰易懂:
private fun concatenation(a: Int, b: Int, c: Map<String, String>): String { return a.plus(b).toString().plus(c.values.toString()) } private fun subtraction(a: Int, b: Int): Int { return a - b } @Test fun test() { val tasks = listOf( { concatenation(1, 2, mapOf("S" to "M")) }, { subtraction(5, 3) } ) val results = tasks.map { it() } results.forEach { println(it) } }
方案二:反射callBy方法(适合必须用反射的场景)
如果一定要用函数引用和反射,使用KFunction的callBy方法替代invoke:它接受参数映射,自动匹配参数与实例,无需担心参数数量问题:
private fun concatenation(a: Int, b: Int, c: Map<String, String>): String { return a.plus(b).toString().plus(c.values.toString()) } private fun subtraction(a: Int, b: Int): Int { return a - b } @Test fun test() { val methodArgsPairs = listOf( ::concatenation to listOf(1, 2, mapOf("S" to "M")), ::subtraction to listOf(5, 3) ) val results = methodArgsPairs.map { (method, args) -> if (method.parameters.size == args.size) { // 构建参数索引与值的映射 val paramMap = method.parameters.zip(args).toMap() method.callBy(paramMap) } else { "参数数量不匹配" } } results.forEach { println(it) } }
方案三:密封类封装(适合复杂场景)
如果需要结构化管理不同方法调用,用密封类定义调用类型,确保编译期类型安全:
private fun concatenation(a: Int, b: Int, c: Map<String, String>): String { return a.plus(b).toString().plus(c.values.toString()) } private fun subtraction(a: Int, b: Int): Int { return a - b } sealed class MethodCall { data class Concatenation(val a: Int, val b: Int, val c: Map<String, String>) : MethodCall() data class Subtraction(val a: Int, val b: Int) : MethodCall() } @Test fun test() { val calls = listOf( MethodCall.Concatenation(1, 2, mapOf("S" to "M")), MethodCall.Subtraction(5, 3) ) val results = calls.map { call -> when (call) { is MethodCall.Concatenation -> concatenation(call.a, call.b, call.c) is MethodCall.Subtraction -> subtraction(call.a, call.b) } } results.forEach { println(it) } }
内容的提问来源于stack exchange,提问作者firstpostcommenter
相关产品推荐
相关产品推荐

