我怎么能一个类的实例进行比较的类型的接口?

问题描述 投票:0回答:4

我试图实现科特林一个简单的服务定位器,基于this article,但我想使用泛型类型参数。我也想避免与具体化类型参数内联函数,因为需要的一切是公开的。

这个类是负责的位于服务缓存的实例:

class Cache {
    private val services: MutableList<Any> = mutableListOf()

    fun <T> getService(serviceClass: Class<T>): T? {
        val service = services.firstOrNull { s -> s::class.java == serviceClass }

        if (service != null) {
            return service as T
        }

        return null
    }

    fun addService(service: Any) {
        services.add(service)
    }
}

这是高速缓存是如何被称为:

cache.getService(IMyService::class)

它返回null每次,不管它是否包含MyService与否的实例。问题是在s::class.java == serviceClass,因为在运行时的缓存中包含一个实例MyService,并MyService::class.java不等同于IMyService::class(也不是MyService::class - 我想,太)。

我试图修改getService方法如下所示:

fun <T> getService(): T? {
    val service = services.firstOrNull { s -> s is T }

    if (service != null) {
        return service as T
    }

    return null
}

s is T,编译器会抱怨“无法检查擦除类型的实例:T”。我怎样才能使这项工作不内联,这需要服务的名单公之于众?

design-patterns kotlin inversion-of-control service-locator
4个回答
4
投票

如果您能够接受的反射,你可以使用isAssignableFrom检查请求的Class是你缓存的给定Class的超类/超接口:

fun <T> getService(serviceClass: Class<T>): T? {
    return services.firstOrNull { s -> serviceClass.isAssignableFrom(s::class.java) } as T?
}

2
投票

只是回答关于内联问题的另一半,你能避免使用@PublishedApi注释和标记领域internal使地图服务公众。例如:

class Cache {
    @PublishedApi internal val services: MutableList<Any> = mutableListOf()

    inline fun <reified T> getService(serviceClass: Class<T>): T? {
        return T::class.java.let { it.cast(services.firstOrNull(it::isInstance)) }
    }

    fun addService(service: Any) {
        services.add(service)
    }
}

2
投票

由于与@PublishedApi注释,你可以使用is为好,避免反射,使功能确实简洁kcoppock的好主意:

class Cache {
    @PublishedApi internal val services: MutableList<Any> = mutableListOf()

    inline fun <reified T> getService() = services.firstOrNull { it is T } as T?

    // ...
}

0
投票

如果你想保持私人services(或使getService从Java可用),并且仍然保持从科特林更好的可用性,只需添加一个过载:

fun <T> getService(serviceClass: Class<T>): T? { ... }

inline fun <reified T> getService(): T? = getService(T::class.java)
© www.soinside.com 2019 - 2024. All rights reserved.