Kotlin扩展通用函数与基本类型没有反射API
我有一个Java对象具有方法getLong
, getBoolean
和getString
。 我试图做一个通用的扩展函数,它具有作为最后一个参数的功能。 本质上包装的尝试和捕获和调用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反射罐添加到类路径。 如果可能,我想避免这种情况。
UPDATE1:第一个答案和响应使用T::class
when
,实际上并没有工作。 感谢这个想法,它帮助我再次看。 第二个我发现比我想要的更“字眼”,所以我结束了这个解决方案。
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 }
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") }
kotlin is
运算符左边is
一个对象,右边是一个类的引用。 您可以只使用简单的相等性检查,因为您已经在两边都有类参考。
T在编译时仍然是未知的,所以把this.get*() as T
并没有什么意义。 你已经在你的block中验证了类型,所以你可以使用它。
作为一个完整的问题,你可能还想包含一个else块,以防有人调用jsonObject.getIt<Date>(...)
。
我还包括了第二个版本,需要一个额外的参数来调用,但听起来像你最初想要的不太冗长的版本。 它需要key
, accessor
和block
,并且可以在将来添加到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) } }