2017-08-19 42 views
1

我正在编写这种通用方法来从Firebase中获取数据?在某些情况下,返回空有效,在其他情况下不是,是否可以检查通用参数是否可以为空?Kotlin - 检查通用参数是否可选?

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("") 
     } 
    } 
} 

回答

3

注:我没有亲自使用火力地堡却又如此的一些下面的例子可能无法编译,但应该足够接近。

Class<T>也没有KClass<T>追踪可空性,因为它们只代表一类。但是,KType可以表示“一个具有可选类型参数的类,并且具有可空性”,并且具有isMarkedNullable属性。

您可以使用reified type parameters获得泛型类型的KClass,但您无法获得(截至Kotlin 1.1)a KType。但是,您仍然可以检查通用类型是否可以为空(nullable reified type : Kotlin)与null is T(感谢sosite对于pointing out,因为null as Ttry/catch中不需要)。


有了这个,只要你可以标记obsrveObjectinline,可以通过 “查看是否泛型参数是可选的还是不”:

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

您可以从returnTypeKCallable<R>得到KType,但你也可以使用createType创建一个KClass<T>一个KType

User::class.createType(nullable = false) // User 
User::class.createType(nullable = true)  // User? 

这里的类是类型的classifier所以这取决于你如何使用obsrveObject你可能会将其参数类型从Class<T>更改为KCallable<T>。你可以将其更改为KType直接并根据需要创建实例,但我猜你抓住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) 
+0

谢谢,返回的结果必须是可选类型的可观察值吗? – aryaxt

+0

那么如果你想要返回'null',那么你需要返回'Observable '或'Observable ?'。如果你想晚点,那么你应该可以'返回null'。 – mfulton26

+0

我希望我能够在需要时将其定义为可选,这在迅速的情况下是可能的,是不是在Kotlin?例如数据,数据,通用类型可以根据需要定义为可选或强制用户 – aryaxt