Kotlin扩展通用函数,基本类型没有反射API

时间:2017-07-21 00:54:15

标签: generics kotlin kotlin-extension

我有一个包含方法getLonggetBooleangetString的Java对象。我试图创建一个具有函数作为最后一个参数的通用扩展函数。基本上包装try和catch并调用可能引发异常的getString等。我发现在调用示例<reified T>时设置的getIt<Long>() { // do something with it }需要反射api才能找出T。我不能做的是检查也不是isInstance。有什么想法吗?

// This is the non generic function version to get an idea
inline fun JSONObject.getItLong(key: String, block: (value: Long) -> Unit) {
    try {
        block(this.getLong(key))
    } catch (e: JSONException) {
        Log.w("${ javaClass.simpleName }KEx", e.message)
    }
}

以下when不起作用。

inline fun <reified T> JSONObject.getIt(key: String, block: (value: T) -> Unit) {
    try {
        when {
            Long is T -> { block(this.getLong(key) as T) }
            String is T -> { block(this.getString(key) as T) }
            // Boolean is T -> { block(this.getBoolean(key) as T) } // Boolean broken, does not have companion object?
        }
    } catch (e: JSONException) {
        Log.w("fetchFromJSONObject", e.message)
    }
}

因此,除了布尔问题之外,我想通过使用T来使用通用的方法来调用正确的get类型。我遇到需要将kaitlin反射jar添加到类路径中。我希望尽可能避免这种情况。

UPDATE1:使用whenT::class的第一个答案和回复实际上无效。谢谢你的想法,它帮我看了一遍。第二个我发现&#34;更多&#34;比我想要的更多,所以我最终得到了这个解决方案。

inline fun <reified T> JSONObject.getIt(key: String, block: (value: T) -> Unit) {
    try {
        block(this.get(key) as T)
    } catch (e: JSONException) {
        Log.w("${ javaClass.simpleName }KEx", e.message)
    }
}

jsonObj.getIt<String>("error") { er = it }

相比,这看起来像jsonObj.getIt<String>("error", JSONObject::getString) { err = it }

UPDATE2:这似乎最终是一种更好的方法,至少对我而言,避免了使用泛型来实现目标的问题

inline fun JSONObject.unless(func: JSONObject.() -> Unit) {
    try {
        this.func()
    } catch (e: JSONException) {
        Log.w("${ javaClass.simpleName }KEx", e.message)
    }
}

使用:

jsonObj.unless {
    sDelay = getLong("s_delay") * 1000
    wDelay = getLong("w_delay") * 1000
}
jsonObj.unless { sam = getBoolean("sam") }
jsonObj.unless { err = getString("error") }

1 个答案:

答案 0 :(得分:1)

kotlin is运算符在左侧获取一个对象,在右侧获取一个类引用。你可以在那里使用简单的相等检查,因为你已经在两边都有类引用。

T在编译时仍然是未知的,因此使用this.get*() as T并没有多大意义。你已经验证了你的阻止时的类型,所以你也可以使用它。

作为完整性问题,您可能还希望在有人拨打jsonObject.getIt<Date>(...)时添加其他阻止。

我还包含了第二个版本,它需要一个额外的参数来调用,但听起来像是你原本想要的一个不那么详细的版本。它需要keyaccessorblock,并且适用于将来添加到JSONObject的任何现有和新访问者,而无需对扩展进行任何修改或修改。

inline fun <reified T> JSONObject.getIt(key: String, block: (value: T) -> Unit) {
    try {
        when (T::class) {
            kotlin.Long::class -> block(this.getLong(key) as Long)
            kotlin.String::class -> block(this.getString(key) as String)
            kotlin.Boolean::class -> block(this.getBoolean(key) as Boolean)
        }
    } catch (e: JSONException) {
        Log.w("fetchFromJSONObject", e.message)
    }
}

inline fun <T> JSONObject.getIt(key: String, accessor: JSONObject.(String) -> T, block: (T) -> Unit) {
    try {
        accessor(key).let(block)
    } catch (e: JSONException) {
        Log.w("fetchFromJSONObject", e.message)
    }
}