如何使用反射动态地转换数组以匹配函数的参数?

时间:2018-12-30 21:47:43

标签: kotlin casting dynamic-cast

我正在一个项目中,我想在其中解析一些输入并使用它来调用函数。输入是在运行时处理的字符串,并且要调用的函数由开发人员指定。标记化的输入将传递到指定的函数。

这演示了如何使用代码。您传入一个函数,一些要解析的东西以及一组可以匹配以生成令牌的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实现,因此可以使用反射将其传递给函数。我也乐于接受其他方式来完成此任务,任何帮助将不胜感激!谢谢!

2 个答案:

答案 0 :(得分:0)

我相信可以通过将基础实现枚举存储或检索到令牌本身中来实现。在此行中,存储了该类,但是我不确定它是指任何颜色还是特定的Color.Red或Color.Green。

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <syncOrderRelationResponse 
       xmlns="http://www.csapi.org/schema/parlayx/data/sync/v1_0/local">
        <result>0</result>
        <resultDescription>OK</resultDescription>
    </syncOrderRelationResponse>
  </soap:Body>
</soap:Envelope

这可能可以恢复,但是我不确定如何写。

tokenPatterns.filter { it.pattern.matches(input) }.map { Token(it::class) }

也许我可以不用强制转换来重新创建枚举了?

答案 1 :(得分:0)

只需将tokenPattern存储到令牌中,然后将这些tokenPattern作为args传递,然后反射就可以正确地对其进行强制转换。

您可以像这样制作令牌:

private fun runIt(func: KFunction<String>, tokens: List<Token>): String {
    val args: Array<Any> = tokens.map { it.original }.toTypedArray()
    return func.call(*args)
}

然后像这样调用函数:

${Properties#fqdn}