In Kotlin gibt es eine eingebaute Unterstützung für delegierte Eigenschaften (delegated properties). Der Mechanismus by ermöglicht es, den Getter/Setter einer beliebigen Eigenschaft an ein spezielles Objekt – den Delegaten – zu delegieren. Die bekanntesten Delegaten sind: lazy, observable, vetoable und benutzerdefinierte.
Vorteile:
Beispiel eines benutzerdefinierten Delegaten:
class UpperCaseDelegate { private var value: String = "" operator fun getValue(thisRef: Any?, property: KProperty<*>): String = value operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: String) { value = newValue.uppercase() } } class Person { var name: String by UpperCaseDelegate() }
Einschränkungen:
Kann ein Delegat, der Zugriff auf den Kontext benötigt (zum Beispiel Android Context), in den Eigenschaften von Begleitobjekten oder im Top-Level-Objekt verwendet werden?
Oft wird fälschlicherweise geantwortet, dass "es immer möglich ist, warum nicht?"
Richtige Antwort: Nein, denn Begleitobjekte und Top-Level-Objekte werden vor der Initialisierung von Instanzen der Klasse oder der Anwendung initialisiert, was zu Fehlern führen kann, die mit dem Zugriff auf einen nicht initialisierten Kontext zu tun haben. Delegaten, die Zugriff auf eine Instanz benötigen, sollten nur in den Eigenschaften einer Klasse verwendet werden.
Geschichte
Delegation der lazy-Initialisierung in Android-ViewModel: Ein Programmierer hat einen heavy-lazy Delegaten in das Begleitobjekt ausgelagert. In einigen Situationen (nach einem SDK-Update) stürzte die Anwendung bei der Initialisierung ab – der Kontext war noch nicht verfügbar, aber der Delegat hatte bereits sein "init" ausgeführt.
Geschichte
Falsche Serialisierung mit Delegaten: Ein benutzerdefinierter Delegat wurde zur Speicherung von Daten verwendet, enthielt jedoch nicht serialisierbare Verweise auf den Kontext. Bei dem Versuch, die Daten zu serialisieren, traten Fehler auf und es gingen Daten verloren.
Geschichte
Observable-Delegat mit fehlerhaftem Rückruf: Ein Entwickler verwendete Delegates.observable, um den Status zu steuern, innerhalb der Lambda-Funktion wurde ein neuer Wert zugewiesen, was zu einer Endlosschleife und StackOverflowError zur Laufzeit führte.