【问题标题】:calling <reified T> inline functions from a class从类中调用 <reified T> 内联函数
【发布时间】:2020-11-30 13:12:27
【问题描述】:

简而言之:我想创建一个类型为 T 的泛型类,它应该调用类型为 T 的具体内联函数,以便能够更通用地使用 Gson

详细说明:
你好。我最近开始将 kotlin 用于 Android 开发,我正在尝试创建一个通用的网络客户端类。该类将从服务器获取数据,将响应转换为泛型类类型提供的数据类型并返回响应,如下所示:

class GenericNetworkService<RESPONSE_TYPE> {

    fun getDataFromServer(url: String): RESPONSE_TYPE {
        val request = Request.Builder().url(url).build()

        val response = OkHttpClient().newCall(request).execute()

        val convertor = Gson()

        val result: RESPONSE_TYPE = convertor.fromJson(response.body!!.string(), RESPONSE_TYPE)

        return result

    }
}

//calling
//fun main() {

//    val listOfPersons = GenericNetworkService<List<Person>>().getDataFromServer(url1)
//    println(listOfPersons)

//    val listOFTeacher = GenericNetworkService<List<Teacher>>().getDataFromServer(url2)
//    println(listOFTeacher)
// }

在这里,只有gson.fromJson() func 是实际需要最终输出必须转换的类的详细信息的函数。 但它没有将泛型类型带入第二个参数,所以上面的程序不起作用。 在搜索了一些互联网文章后,我发现了这个TypeToken Api,它在一定程度上有助于实现通用行为:


inline fun <reified T> fromJson(json: String): T {
   return Gson().fromJson(json, object: TypeToken<T>(){}.type)
}

//calling : 
// val data : List<Teacher> = fromJson(response)

使用内联具体化函数,我能够实现我最初想要的一切:


private inline fun <reified RESPONSE_TYPE> getGenericRespSync(url: String): RESPONSE_TYPE {
    val okHttpClient = generateNetworkClient()
    val request = Request.Builder().url(url).build()
    val response: Response = okHttpClient.newCall(request).execute()

    val body: Reader = response.body!!.charStream()
    val finalResponse: RESPONSE_TYPE =  getConvertedListForResponse(body) //this is the same reified inline function as above with some non signinficant additions
    return finalResponse
}


但我希望我的其他类通过某个类实例调用此函数。即像 GenericNetworkService&lt;List&lt;Person&gt;&gt;().getGenericRespSync(url1) 这样的东西应该返回 List 而不是直接调用 getGenericRespSync(url1) 。我怎样才能实现这样的功能?

【问题讨论】:

    标签: kotlin generics gson


    【解决方案1】:

    嗯,你可以定义

    inline fun <reified RESPONSE_TYPE> GenericNetworkService<RESPONSE_TYPE>.getGenericRespSync1(url: String): RESPONSE_TYPE = getGenericRespSync<RESPONSE_TYPE>(url)
    

    (我以不同的方式命名该函数,以便它可以调用您之前定义的getGenericRespSync)。当然,它只使用它被调用的实例来获取它的类型参数,否则忽略它。

    【讨论】:

      【解决方案2】:

      不幸的是,类构造函数不能使用与内联函数相同的reified 机制。但是,您可以将类型定义为常规构造函数参数,并使用顶级内联函数创建类的新实例

      class GenericNetworkService<RESPONSE_TYPE>(private val responseTypeClass: Class<RESPONSE_TYPE>) {
      
          fun getDataFromServer(url: String): RESPONSE_TYPE {
              val request = Request.Builder().url(url).build()
      
              val response = OkHttpClient().newCall(request).execute()
      
              val convertor = Gson()
      
              val result: RESPONSE_TYPE = convertor.fromJson(response.body!!.string(), responseTypeClass)
      
              return result
      
          }
      }
      
      inline fun <reified RESPONSE_TYPE> createService() = GenericNetworkService(RESPONSE_TYPE::class.java)
      

      当然,您也可以将createService 重命名为GenericNetworkService,使其看起来像一个构造函数。这在 kotlin 中变得越来越普遍,特别是如果您查看协程核心代码,所以我不会再认为这是一种反模式。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-06
        • 1970-01-01
        • 2014-03-04
        • 2020-06-18
        相关资源
        最近更新 更多