首页 文章

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

提问于
浏览
0

我有一个Java对象,它有方法 getLonggetBooleangetString . 我试图创建一个具有函数作为最后一个参数的通用扩展函数 . 基本上包装try和catch并调用可能引发异常的 getString 等 . 我发现调用例如 getIt<Long>() { // do something with it } 时设置的 <reified T> 需要反射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 的第一个答案和响应实际上不起作用 . 谢谢你的想法,它帮我看了一遍 . 第二个我找到"wordier"比我想要的,所以我最终得到了这个解决方案 .

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", JSONObject::getString) { err = it } 相比,这看起来像 jsonObj.getIt<String>("error") { er = it }

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

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 回答

  • 1

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

    T在编译时仍然是未知的,所以考虑 this.get*() as T 不会't make a whole lot of sense. You'll已经验证了你的块中的类型,所以你也可以使用它 .

    作为完整性问题,您可能还希望包含一个else块,以防有人调用 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)
        }
    }
    

相关问题