【问题标题】:Can I pass type information to simplify this somehow?我可以传递类型信息以某种方式简化吗?
【发布时间】:2017-03-31 03:16:43
【问题描述】:

我有很多这样的代码,除了类型PositionJson之外都一样,可能是AnotherJsonFooJsonBarJson

有什么方法可以将所有这些代码提取到一个函数中,然后我可以以某种方式将类型传递给它?这样我的课堂上就不会有几块几乎相同的代码?

我不确定这是否可能,只是想我会问,因为这样做会很好......

    /**
     * @return the _open_ [PositionJson]s
     */
    val positions: Array<PositionJson>?
        @Throws(AccountsAPIException::class)
        get() {
            val service = constructServiceURL(POSITIONS, null, true)
            try {
                val messageJson = mapper.readValue<MessageJson<Array<PositionJson>>>(
                        callURL(service),
                        object: TypeReference<MessageJson<Array<PositionJson>>>() {

                        })

                val error = messageJson.error
                if (error != null) throw AccountsAPIException(error.errorCode, error.description)
                return messageJson.data
            } catch (e: Exception) {
                throw AccountsAPIException(e)
            }
        }

【问题讨论】:

    标签: json jackson kotlin


    【解决方案1】:

    你可以用泛型做你想做的事。但是,要使用泛型,我们首先需要将这段巨大的代码块提取到一个方法中:

    val positions: Array<PositionJson>? get() = getPositions()
    
    fun getPositions(): Array<PositionJson>? {
        ...
    }
    

    我们还没有解决这个问题,但现在我们可以通过将getPositions 设为泛型来解决它(注意我还重命名了函数):

    val positions: Array<PositionJson> get() = getArrayOf<PositionJson>()
    // thanks to type inference I can omit the type on getArrayOf if desired:
    val positions: Array<PositionJson> get() = getArrayOf()
    
    fun <T> getArrayOf(): Array<T>? {
        val service = constructServiceURL(POSITIONS, null, true)
        try {
            val messageJson = mapper.readValue<MessageJson<Array<T>>>(
                    callURL(service),
                    object: TypeReference<MessageJson<Array<T>>>() {
    
                    })
    
            val error = messageJson.error
            if (error != null) throw AccountsAPIException(error.errorCode, error.description)
            return messageJson.data
        } catch (e: Exception) {
            throw AccountsAPIException(e)
        }
    }
    

    完美!由于类型擦除,这不会编译。但是我们也可以通过将函数设为inline 并将类型参数设为reified 来解决此问题:

    inline fun <reified T: Any> getArrayOf(): Array<T>? {
        ...
    }
    

    应该这样做。现在你可以根据需要重用这个函数了:

    val positions: Array<PositionJson>? get() = getArrayOf()
    val persons: Array<PersonJson>? get() = getArrayOf()
    val bananas: Array<BananaJson>? get() = getArrayOf()
    
    inline fun <reified T: Any> getArrayOf(): Array<T>? {
        val service = constructServiceURL(POSITIONS, null, true)
        try {
            val messageJson = mapper.readValue<MessageJson<Array<T>>>(
                    callURL(service),
                    object: TypeReference<MessageJson<Array<T>>>() {
    
                    })
    
            val error = messageJson.error
            if (error != null) throw AccountsAPIException(error.errorCode, error.description)
            return messageJson.data
        } catch (e: Exception) {
            throw AccountsAPIException(e)
        }
    }
    

    最后一件事:请注意,在我的所有示例中,我都使用了原始代码中的属性获取器 (get() = ...)。但是,我强烈怀疑您不想使用吸气剂。每次有人访问您的属性时都会调用 Getter,在这种情况下,这意味着每次有人读取 positions 属性时,您都会调用 constructServiceURL 并进行服务调用等。如果您希望该代码只发生一次然后你应该只调用一次getArrayOf() 并将结果分配给你的属性:

    val positions: Array<PositionJson>? = getArrayOf()
    // this syntax would also work:
    val positions = getArrayOf<PositionJson>()
    

    【讨论】:

    • 我也刚刚注意到 POSITIONS 变量,OP 在原始问题中没有提到它。这可能也可以作为函数调用的参数提取出来:getArrayOf&lt;PositionJson&gt;(POSITIONS)
    • 是的POSITIONS只是一个url片段,可以很方便的做成参数
    • 我似乎遇到了object: TypeReference&lt;MessageJson&lt;Array&lt;T&gt;&gt;&gt;() { 这一行的障碍——它会产生一个类型转换异常(java.lang.Object cannot be cast....)——如果我将此行上的T 替换为,例如PositionJson 然后它工作 - 我该怎么办?我的意思是代码中的其他Ts 都可以,只有这个有问题
    • @ycomp 您的*Json 对象从哪个通用类派生?或者,编译器抱怨它不能转换到哪个类?假设类名是JsonBase - 更改您的通用签名以要求TJsonBase 的子类:inline fun &lt;reified T: JsonBase&gt; getArrayOf()
    • 就是这样......它们仅扩展 Object/Any(我的意思是在类定义中没有指定任何内容)。它抱怨转换为 Object java.lang.Object cannot be cast.... - 我想这没关系,但它们是 Kotlin 类 - 不是 java 类
    猜你喜欢
    • 1970-01-01
    • 2015-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-14
    • 2023-03-18
    • 1970-01-01
    相关资源
    最近更新 更多