Kotlin - 检查泛型参数是否可选?
Kotlin - Check to see if the generic parameter is optional or not?
我正在编写这个通用方法来从 firebase 获取数据?在某些情况下返回 null 是有效的,在其他情况下则无效,是否可以检查泛型参数是否可为空?
前
reference.obsrveObject(User.class)
如果为空则应该抛出
reference.obsrveObject(User?.class)
应该用空值调用 onNext
fun DatabaseReference.observeSingleEvent(): Observable<DataSnapshot?> {
return Observable.create { subscriber ->
val valueEventListener = object: ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot?) {
subscriber.onNext(snapshot)
subscriber.onCompleted()
}
override fun onCancelled(error: DatabaseError?) {
subscriber.onError(FirebaseDatabaseThrowable(error))
}
}
addListenerForSingleValueEvent(valueEventListener)
}
}
fun <T>DatabaseReference.obsrveObject(clazz: Class<T>): Observable<T> {
return observeSingleEvent().map { snapshot ->
if (snapshot != null) {
snapshot.getValue(clazz)
}
else {
// if clazz is nullable return null
// if clazz is not nullabel throw
throw Exception("")
}
}
}
注意:我还没有亲自使用过 Firebase,所以下面的一些示例可能无法编译,但应该足够接近了。
都没有 Class<T>
nor KClass<T>
track nullability as they only represent a class. A KType
, however, can represent "a class with optional type arguments, plus nullability" and has an isMarkedNullable
属性.
您可以使用 reified type parameters to get a KClass
for the generic type but you cannot get (as of Kotlin 1.1) a KType
. However, you can still check to see if the generic type is nullable (nullable reified type : Kotlin) with null is T
(thanks to sosite for ,不需要将 null as T
包裹在 try
/catch
中)。
有了这个,只要能把obsrveObject
标记为inline
,就可以"check to see if the generic parameter is optional or not":
inline fun <reified T> DatabaseReference.obsrveObject(): Observable<T> {
return observeSingleEvent().map { snapshot ->
if (snapshot != null) {
snapshot.getValue(T::class.java)
} else if (null is T) {
null as T
} else {
throw Exception("")
}
}
}
用法:
databaseReference.obsrveObject<User>() // Observable<User>
databaseReference.obsrveObject<User?>() // Observable<User?>
如果您不能使用内联函数(因此不能使用具体化的类型参数),那么您需要找到一种方法来获得 KType
.
您可以从 KCallable<R>
上的 returnType
获得 KType
,但您也可以使用 [=43= 从 KClass<T>
创建 KType
]:
User::class.createType(nullable = false) // User
User::class.createType(nullable = true) // User?
此处的 class 是类型的 classifier
因此根据您使用 obsrveObject
的方式,您可以将其参数类型从 Class<T>
更改为 KCallable<T>
.您可以直接将其更改为 KType
并根据需要创建实例,但我猜您目前正在从 属性 的 return 类型中获取 clazz
所以我会选择KCallable<T>
:
fun <T : Any> DatabaseReference.obsrveObject(callable: KCallable<T>): Observable<T?> {
val kType = callable.returnType
val kClass = kType.classifier as KClass<T>
val clazz = kClass.java
return observeSingleEvent().map { snapshot ->
if (snapshot != null) {
snapshot.getValue(clazz)
} else if (kType.isMarkedNullable) {
null
} else {
throw Exception("")
}
}
}
然后您可以使用对可调用对象(属性、函数等)的引用来调用它:
databaseReference.obsrveObject(session::user)
我正在编写这个通用方法来从 firebase 获取数据?在某些情况下返回 null 是有效的,在其他情况下则无效,是否可以检查泛型参数是否可为空?
前
reference.obsrveObject(User.class)
如果为空则应该抛出
reference.obsrveObject(User?.class)
应该用空值调用 onNext
fun DatabaseReference.observeSingleEvent(): Observable<DataSnapshot?> {
return Observable.create { subscriber ->
val valueEventListener = object: ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot?) {
subscriber.onNext(snapshot)
subscriber.onCompleted()
}
override fun onCancelled(error: DatabaseError?) {
subscriber.onError(FirebaseDatabaseThrowable(error))
}
}
addListenerForSingleValueEvent(valueEventListener)
}
}
fun <T>DatabaseReference.obsrveObject(clazz: Class<T>): Observable<T> {
return observeSingleEvent().map { snapshot ->
if (snapshot != null) {
snapshot.getValue(clazz)
}
else {
// if clazz is nullable return null
// if clazz is not nullabel throw
throw Exception("")
}
}
}
注意:我还没有亲自使用过 Firebase,所以下面的一些示例可能无法编译,但应该足够接近了。
都没有 Class<T>
nor KClass<T>
track nullability as they only represent a class. A KType
, however, can represent "a class with optional type arguments, plus nullability" and has an isMarkedNullable
属性.
您可以使用 reified type parameters to get a KClass
for the generic type but you cannot get (as of Kotlin 1.1) a KType
. However, you can still check to see if the generic type is nullable (nullable reified type : Kotlin) with null is T
(thanks to sosite for null as T
包裹在 try
/catch
中)。
有了这个,只要能把obsrveObject
标记为inline
,就可以"check to see if the generic parameter is optional or not":
inline fun <reified T> DatabaseReference.obsrveObject(): Observable<T> {
return observeSingleEvent().map { snapshot ->
if (snapshot != null) {
snapshot.getValue(T::class.java)
} else if (null is T) {
null as T
} else {
throw Exception("")
}
}
}
用法:
databaseReference.obsrveObject<User>() // Observable<User>
databaseReference.obsrveObject<User?>() // Observable<User?>
如果您不能使用内联函数(因此不能使用具体化的类型参数),那么您需要找到一种方法来获得 KType
.
您可以从 KCallable<R>
上的 returnType
获得 KType
,但您也可以使用 [=43= 从 KClass<T>
创建 KType
]:
User::class.createType(nullable = false) // User
User::class.createType(nullable = true) // User?
此处的 class 是类型的 classifier
因此根据您使用 obsrveObject
的方式,您可以将其参数类型从 Class<T>
更改为 KCallable<T>
.您可以直接将其更改为 KType
并根据需要创建实例,但我猜您目前正在从 属性 的 return 类型中获取 clazz
所以我会选择KCallable<T>
:
fun <T : Any> DatabaseReference.obsrveObject(callable: KCallable<T>): Observable<T?> {
val kType = callable.returnType
val kClass = kType.classifier as KClass<T>
val clazz = kClass.java
return observeSingleEvent().map { snapshot ->
if (snapshot != null) {
snapshot.getValue(clazz)
} else if (kType.isMarkedNullable) {
null
} else {
throw Exception("")
}
}
}
然后您可以使用对可调用对象(属性、函数等)的引用来调用它:
databaseReference.obsrveObject(session::user)