2017-08-19 60 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