如何使用反射动态转换数组以匹配函数的参数?
How can I dynamically cast an array to match a function's arguments using reflection?
我正在做一个项目,我想在其中解析一些输入并用它来调用一个函数。输入是运行时处理的字符串,调用的函数由开发者指定。标记化的输入将传递给指定的函数。
这演示了如何使用代码。您传入一个函数、要解析的内容和一组可以匹配以生成令牌的 tokenPatterns。
fun main(args : Array<String>) {
val f = Funcs()
val myColor: String = f.whatColor(Color.GREEN) // Expected
val theirColor: String = Processor.process(f::whatColor, "green", Color.values().toSet())
println(myColor == theirColor) // Should be true
}
class Funcs {
fun whatColor(color: Color): String {
return when (color) {
Color.RED -> "nice red"
Color.GREEN -> "cool green"
}
}
}
enum class Color(override val pattern: Regex) : TokenPattern {
RED(Regex("red")),
GREEN(Regex("green"))
}
下面的代码显示了它当前如何工作(或不能工作)的基本版本。本质上,我根据 tokenPatterns 集对输入进行标记,然后使用这些标记调用指定的函数。问题是我需要将它们转换回模式的原始实现(在本例中为 Color 枚举),以便我可以用它们调用原始函数。
/**
* Extend to define custom tokens.
*/
interface TokenPattern {
val pattern: Regex
}
class Token<T: Any>(val type: KClass<out T>)
/**
* Tokenizes and runs functions
*/
object Processor {
fun process(func: KFunction<String>, input: String, tokenPatterns: Set<TokenPattern>): String {
val tokens = tokenize(input, tokenPatterns)
return runIt(func, tokens)
}
private fun tokenize(input: String, tokenPatterns: Set<TokenPattern>): List<Token<*>> {
return tokenPatterns.filter { it.pattern.matches(input) }.map { Token(it::class) }
}
private fun runIt(func: KFunction<String>, tokens: List<Token<*>>): String {
val args: Array<Any> = tokens.toTypedArray()
// Some casting needs to be done
return func.call(*args)
}
实际代码比这复杂,但这或多或少说明了它是如何协同工作的。我遇到的主要问题是我不确定如何动态转换回 Color 实现,以便我可以使用反射将它传递给函数。我也愿意接受其他方式来完成这项任务,任何帮助将不胜感激!谢谢!
我相信这可以通过将底层实现枚举存储或检索到令牌本身来实现。在这一行中,存储了 class,但我不确定它是指任何颜色还是特定的 Color.Red 或 Color.Green.
tokenPatterns.filter { it.pattern.matches(input) }.map { Token(it::class) }
这可能是这样恢复的,但我不确定具体怎么写。
val castedArgs: Array<Any> = tokens.map { it.type.cast(it) }.toTypedArray()
也许我可以用某种方式重新创建枚举而不是强制转换?
只需将 tokenPattern 存储到令牌中,将这些 tokenPattern 作为参数传递,反射将能够适当地转换它。
你可以这样制作令牌:
class Token(val original: TokenPattern)
然后像这样调用函数:
private fun runIt(func: KFunction<String>, tokens: List<Token>): String {
val args: Array<Any> = tokens.map { it.original }.toTypedArray()
return func.call(*args)
}
我正在做一个项目,我想在其中解析一些输入并用它来调用一个函数。输入是运行时处理的字符串,调用的函数由开发者指定。标记化的输入将传递给指定的函数。
这演示了如何使用代码。您传入一个函数、要解析的内容和一组可以匹配以生成令牌的 tokenPatterns。
fun main(args : Array<String>) {
val f = Funcs()
val myColor: String = f.whatColor(Color.GREEN) // Expected
val theirColor: String = Processor.process(f::whatColor, "green", Color.values().toSet())
println(myColor == theirColor) // Should be true
}
class Funcs {
fun whatColor(color: Color): String {
return when (color) {
Color.RED -> "nice red"
Color.GREEN -> "cool green"
}
}
}
enum class Color(override val pattern: Regex) : TokenPattern {
RED(Regex("red")),
GREEN(Regex("green"))
}
下面的代码显示了它当前如何工作(或不能工作)的基本版本。本质上,我根据 tokenPatterns 集对输入进行标记,然后使用这些标记调用指定的函数。问题是我需要将它们转换回模式的原始实现(在本例中为 Color 枚举),以便我可以用它们调用原始函数。
/**
* Extend to define custom tokens.
*/
interface TokenPattern {
val pattern: Regex
}
class Token<T: Any>(val type: KClass<out T>)
/**
* Tokenizes and runs functions
*/
object Processor {
fun process(func: KFunction<String>, input: String, tokenPatterns: Set<TokenPattern>): String {
val tokens = tokenize(input, tokenPatterns)
return runIt(func, tokens)
}
private fun tokenize(input: String, tokenPatterns: Set<TokenPattern>): List<Token<*>> {
return tokenPatterns.filter { it.pattern.matches(input) }.map { Token(it::class) }
}
private fun runIt(func: KFunction<String>, tokens: List<Token<*>>): String {
val args: Array<Any> = tokens.toTypedArray()
// Some casting needs to be done
return func.call(*args)
}
实际代码比这复杂,但这或多或少说明了它是如何协同工作的。我遇到的主要问题是我不确定如何动态转换回 Color 实现,以便我可以使用反射将它传递给函数。我也愿意接受其他方式来完成这项任务,任何帮助将不胜感激!谢谢!
我相信这可以通过将底层实现枚举存储或检索到令牌本身来实现。在这一行中,存储了 class,但我不确定它是指任何颜色还是特定的 Color.Red 或 Color.Green.
tokenPatterns.filter { it.pattern.matches(input) }.map { Token(it::class) }
这可能是这样恢复的,但我不确定具体怎么写。
val castedArgs: Array<Any> = tokens.map { it.type.cast(it) }.toTypedArray()
也许我可以用某种方式重新创建枚举而不是强制转换?
只需将 tokenPattern 存储到令牌中,将这些 tokenPattern 作为参数传递,反射将能够适当地转换它。
你可以这样制作令牌:
class Token(val original: TokenPattern)
然后像这样调用函数:
private fun runIt(func: KFunction<String>, tokens: List<Token>): String {
val args: Array<Any> = tokens.map { it.original }.toTypedArray()
return func.call(*args)
}