Общая функция расширения Котлина с базовыми типами без отражения API

У меня есть объект Java, который имеет методы getLong , getBoolean и getString . Я попытался создать общую функцию расширения, которая имеет функцию в качестве последнего параметра. По сути, обертывание try и catch и вызов getString т. Д., 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) } } 

Таким образом, помимо булевской проблемы, я хотел иметь общий способ вызвать правильный тип get, используя T Я столкнулся с необходимостью добавить кувшин для отражения кайтлин в путь к классам. Я хотел избежать этого, если это возможно.

UPDATE1: первый ответ и ответ с использованием, when с T::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") { 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 принимает объект слева и ссылку на класс справа. Вы можете просто использовать простую проверку равенства, поскольку у вас уже есть ссылки на классы с обеих сторон.

T пока неизвестно во время компиляции, поэтому, принимая this.get*() as T не имеет большого смысла. Вы уже проверили тип в своем блоке, чтобы вы могли его использовать.

В качестве полноты вы, вероятно, захотите также включить блок 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) } }