【问题标题】:Why is my Realm Kotlin Generics workaround not working as expected?为什么我的 Realm Kotlin 泛型解决方法没有按预期工作?
【发布时间】:2018-07-05 10:13:18
【问题描述】:

我知道 Realm 还没有直接支持泛型。我一直在尝试想出一个解决方法,因为它会极大地减少我的项目中的重复代码。 (我有许多扩展基础 repo 的 repos 和许多仅因 RealmObject 扩展类型而不同的函数)

我有一个相当不错的解决方案:

open class BaseRepository(private val realm: Realm) {

    fun <T : RealmModel> get(ofType: Class<T>, id: Long): T? {
        return realm.where(ofType).equalTo("id", id).findFirst()
    }  
}

这可以由我的从 BaseRepository 继承的存储库调用,如下所示:

customRepository.get(CustomType::class.java, id)

我试图通过在构造函数中传递类类型而不是函数参数来进一步改进这一点:

open class BaseRepository<T : RealmModel?>(private val realm: Realm, private val ofType: Class<T>) {

    fun <T : RealmModel> get(id: Long): T? {
        return realm.where(ofType).equalTo("id", id).findFirst()
    }
}

上面有如下编译时错误:

Type mismatch.
Required: T#1 (type parameter of com.acme.data.repository.BaseRepository.get)?
Found:    T#2 (type parameter of com.acme.data.repository.BaseRepository)?

我已经进行了各种尝试以使其正常工作,但仍然没有成功。

问题:

  1. 为什么我不能在构造函数参数中传递 ofType: Class 而在函数参数中可以?

  2. 有人知道怎么解决吗?

  3. 是否存在任何问题,无论是 Realm 还是其他,我正在做的事情似乎确实有效并且我的所有测试仍然通过?

  4. 有没有人对此有更好的解决方案,例如使用 kotlin 扩展方法?

谢谢, 保罗。

【问题讨论】:

    标签: generics kotlin realm


    【解决方案1】:

    实际上,如果将类传递给超类,则不再需要为函数使用模板参数。

    open class BaseRepository<T : RealmModel>(private val realm: Realm, private val ofType: Class<T>) {
    
        fun get(id: Long): T? =
            realm.where(ofType).equalTo("id", id).findFirst()
    }
    

    一个有趣的消息是,使用 Kotlin,您可以使用 inline &lt;reified T&gt; 减少 ::class.java

    open class BaseRepository(private val realm: Realm) {
    
        inline fun <reified T : RealmModel> get(id: Long): T? =
            realm.where(T::class.java).equalTo("id", id).findFirst()
    }
    

    或者,如果您使用的是较新版本的 Realm (4.3.1+),那么您可以将其更改为

    import io.realm.kotlin.where
    
    open class BaseRepository(private val realm: Realm) {
    
        inline fun <reified T : RealmModel> get(id: Long): T? =
            realm.where<T>().equalTo("id", id).findFirst()
    }
    

    我只是在向你抛出一些想法,但你可以从技术上将它变成一个扩展函数

    inline fun <reified T : RealmModel> Realm.get(id: Long): T? =
        where<T>().equalTo("id", id).findFirst()
    

    现在你可以做

    val dog = realm.get<Dog>(12L)
    

    【讨论】:

    • 这太棒了,谢谢。我接受了第一个建议,因为它允许我在存储库构建期间仅指定一次 ClassType,我可以在我的代码库中调用 repo.get(12L) 并且类型是基于特定存储库已知的,而无需我 它在呼叫点。我试图按照建议减少“::class.java”,但遇到了一些错误,所以我会玩弄它。这不仅回答了我的问题,再次感谢!
    猜你喜欢
    • 1970-01-01
    • 2020-01-10
    • 1970-01-01
    • 2020-02-29
    • 1970-01-01
    • 1970-01-01
    • 2023-01-05
    • 1970-01-01
    • 2019-08-28
    相关资源
    最近更新 更多