2017-06-10 10 views
4

私のクラスのプロパティの値が変更されたことを検出したいので、その後に別の操作を行うことができます。言い換えると、プロパティの特定のデータの1つが変更された場合、特定のイベントがそれまでに発生します。実際には、それがJavaのような別のプログラミング言語で普通のクラスであれば、データが変更された後、あるいはC#でデリゲートを使用したあと、セッターを使ってこの仕事をすることができると思います。しかし、Kotlinは非常に新しくなって以来、私は何の解決策も見つけられませんでした。 私はプロパティをオーバーロードしようとしましたが、万一チャンスがありませんでした。私はこれにもインターフェイスを使用したいと思っていましたが、それはデータクラスであるから、どうすればいいのか分かりません。データクラスKotlinで変更された値を検出する方法は?

以下はサンプルクラスです。このような状況で、年齢や名前が変更されたときを検出する方法はありますか?

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

だから誰でもこれについてのアイデアがあれば、助けてください。

注:私の状況では、データクラスを使用する必要があります。

+0

データクラスの例がコンパイルされない – voddan

+0

データクラスの代わりに通常のクラスを使用できない場合、このような状況はありません。ただ言って。 – voddan

答えて

7

データクラスは本当にこのためを作っていません。そのプロパティはプライマリコンストラクタで宣言する必要があるため、カスタムビヘイビアを実際に追加することはできません。

あなたがしなければならないことは、プロパティを複製し、次にカスタムセッター、またはDelegates.observableを使用してこれを達成できるということです。ここで

は、カスタムセッターでそれを行う方法ですが、ここであなたはつもりにも最新のコンストラクタで宣言されたものを保つ公開さ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 
     } 

} 

トンのいずれかの

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 
    } 

} 

使用法:ここにあなたの唯一のオーバーヘッドが新しい値にコンストラクタで宣言されたプロパティを設定して、あなたのための作業の一部を行いDelegates.observableと同じ考え方、あなたがあるためにあなたのクラスを必要としなかった場合は

:以下の質問に答えるために

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 

編集:HESEは、この(toStringは、アンダースコアで少し醜いになります)のように見えますデータクラスでは、おそらく最も簡単な解決策は次のとおりです。

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

} 

このようにして、 d ageをパラメータとして指定しますが、クラス本体の内部にあるプロパティに割り当てられます。データクラスのすべてのコンストラクタパラメータはプロパティでなければならないため(valまたはvarとマークされている)、これはデータクラスでは不可能です。詳細については、constructors,propertiesおよびdata classesに関するドキュメントをご覧ください。

+0

「プロパティをプライマリコンストラクタで宣言する必要があるため、カスタムビヘイビアを実際に追加することはできません。それは私をもっと好奇心にさせる。そのプロパティをプライマリコンストラクタで宣言する必要がない場合はどうしますか?データの提供はどうですか?通常、コンストラクタを使って供給しますから、それはできませんか? – jujuzi

+0

回答を編集しました。役立つと思っています。 – zsmb13

+0

それは良いものです。しかし、私はもう少し興味がある。 Delegate.observableを使用する目的は何ですか?なぜ 使用して "VAR名:文字列をDelegates.observable(_name) によって{ \t小道具、古い、新しい - >のprintln(" 名前が$から変更古い$に新しい ")_name =新しい }" Iながら、使用できる可能性があります "012名前:文字列=" " \tセット(値){フィールド=値} }" – jujuzi

0

委任プロパティ

我々は 手動で、我々はそれらを必要とするたびにそれらを実装することができますが、一度実装 に、すべてのために非常にいいだろう、という性質の特定の一般的な種類があります、ライブラリに入れてください。例としては、

怠惰な性質のものが含まれます。値は、最初のアクセス時に計算 観測可能なプロパティを取得します:リスナーが 各プロパティの代わりに別のフィールドで、マップのプロパティを格納し、この プロパティの変更に関する通知を得ます。

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

構文は次のとおりです:valのは/ var:することにより、これらの(および他の)ケースをカバーするために、Kotlinは 委任プロパティをサポートしています。 に対応するget()(およびset())は、そのgetValue()およびsetValue()メソッドに委譲されるため、by の後に代理人が代入されます。 メソッド。プロパティデリゲートはインターフェイスを実装する必要はありませんが、 は、getValue()関数(およびsetValue() - var)を提供する必要があります。たとえば:

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.'") 
    } 
} 
関連する問題