2017-06-10 22 views
4

我想檢測我的類的屬性已更改的任何值,以便在此之後我可以執行另一個操作。換句話說,如果一個屬性的特定數據中的一個發生了變化,那麼一個特定的事件就會發生。實際上,如果它是另一種編程語言(如Java)中的普通類,那麼我認爲在數據修改完畢或在C#中使用委託之後,我可以使用setter來完成這項工作。但由於Kotlin非常新,我根本找不到任何解決方案。 我試圖超載財產,但沒有任何機會成功。我也想用接口來解決這個問題,但是由於它是數據類,我不知道該怎麼做。如何檢測Data class Kotlin中更改的值?

下面是示例類。在這種情況下,如何檢測年齡或名稱更改的時間?

data class Person(var Name: String, var Age: Int) 

所以請,如果有人對此有任何想法,請幫助。

注意:在我的情況下,必須使用數據類。

+0

你的數據類的例子並不編譯 – voddan

+0

有*當一個普通班不能代替數據類的無*這樣的情況。只是說。 – voddan

回答

7

數據類是真的沒有爲此做出。由於它們的屬性必須在主構造函數中聲明,所以您無法真正向它們添加自定義行爲。這就是說,如果你必須的話,你可以通過複製屬性來實現這一點,然後使用自定義設置器或者Delegates.observable

這裏是一種定製的setter方法來做到這一點,在這裏你會被訪問的公開可見nameage屬性,守在構造函數中聲明的那些最新的,以及:

data class Person(private var _name: String, private var _age: Int) { 

    var name = _name 
     set(value) { 
      println("Name changed from $name to $value") 
      field = value // sets the backing field for `name` 
      _name = value // sets the `_name` property declared in the primary ctor 
     } 

    var age = _age 
     set(value) { 
      println("Age changed from $age to $value") 
      field = value 
      _age = value 
     } 

} 

同樣的想法,與Delegates.observable,其中做了一些工作的你,在這裏你只開銷設置在構造函數聲明爲新值的屬性:

data class Person(private var _name: String, private var _age: Int) { 

    var name: String by Delegates.observable(_name) { prop, old, new -> 
     println("Name changed from $old to $new") 
     _name = new 
    } 

    var age: Int by Delegates.observable(_age) { prop, old, new -> 
     println("Age changed from $old to $new") 
     _age = new 
    } 

} 

任的T用法HESE看起來像這樣(的toString看起來有點醜與下劃線):

val sally = Person("Sally", 50) 
println(sally)  // Person(_name=Sally, _age=50) 
sally.age = 51  // Age changed from 50 to 51 
println(sally)  // Person(_name=Sally, _age=51) 
println(sally.name) // Sally 
println(sally.age) // 51 

編輯回答以下問題:

如果您並不需要你的類是數據類,下面很可能是最簡單的辦法:

class Person(name: String, age: Int) { 

    var name: String by Delegates.observable(name) { _, old, new -> 
     println("Name changed from $old to $new") 
    } 

    var age: Int by Delegates.observable(age) { _, old, new -> 
     println("Age changed from $old to $new") 
    } 

} 

這樣,你仍然有一個構造函數名稱的年齡作爲參數,但它們被分配到類內部的屬性。這是不可能的與數據類,因爲一個數據類的每一個構造參數必須是一個屬性,以及(標valvar)。欲瞭解更多,您可以看到constructorsproperties,並data classes的文檔。

+0

當你說:「由於它們的性質有主構造中聲明,你真的不能添加自定義的行爲給他們。」這讓我更加好奇。如果他們的屬性不必在主構造器中聲明,你會怎麼做?而如何提供數據?因爲通常我們通過構造函數來提供它,不是嗎? – jujuzi

+0

我已經編輯了我的答案和答案,希望它有幫助。 – zsmb13

+0

好吧..這是一個很好的。但我仍然好奇一點。只是好奇使用Delegate.observable的目的是什麼?使用爲什麼 「變種名稱:String通過對Delegates.observable(_name) { \t道具,舊,新 - >的println(」 名稱由$變爲舊到新的$ 「)_name =新 }」 而我可以使用 「var name:String =」「 \t set(value){field = value} }」 – jujuzi

0

委託屬性

有一些常見類型的屬性,即,儘管我們可以 手動每次我們需要的時候實現它們,將是非常不錯的 實現一勞永逸,並放入圖書館。實例包括

延遲屬性:值被僅在第一接入計算機,可觀察到的 性能:聽衆收到通知變更本 屬性,在地圖存儲的屬性,而不是一個獨立字段 每個屬性。爲了覆蓋這些(和其他)的情況下,支持科特林委派 屬性:

class Example { 
    var p: String by Delegate() 
} 

的語法是:VAL/VAR:通過。因爲後面的表達式 是委託,因爲get()(和set())對應的 屬性將被委託給它的getValue()和setValue() 方法。屬性代表不必實現任何接口,但是他們必須提供getValue()函數(和setValue() - 用於 var's)。例如:

class Delegate { 
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String { 
     return "$thisRef, thank you for delegating '${property.name}' to me!" 
    } 

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { 
     println("$value has been assigned to '${property.name} in $thisRef.'") 
    } 
}