In Kotlin c'è il supporto integrato per le proprietà delegate (delegated properties). Il meccanismo by permette di delegare il getter/setter di qualsiasi proprietà a un oggetto specializzato — il delegato. I delegati più conosciuti sono: lazy, observable, vetoable e i delegati personalizzati.
Vantaggi:
Esempio di delegato personalizzato:
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() }
Limitazioni:
È possibile utilizzare un delegato che richiede accesso al contesto (ad esempio, Android Context), nelle proprietà degli oggetti companion o degli oggetti di livello superiore?
Spesso si risponde in modo errato che "si può sempre, perché no?"
Risposta corretta: No, perché gli oggetti companion e gli oggetti di livello superiore vengono inizializzati prima dell'inizializzazione delle istanze di classe o dell'applicazione, il che può portare a errori relativi all'accesso a contesti non inizializzati. I delegati che richiedono accesso all'istanza devono essere utilizzati solo nelle proprietà della classe.
Storia
Delegazione di inizializzazione pigra in Android-ViewModel: Un programmatore ha spostato un delegato heavy-lazy in un oggetto companion. In alcune situazioni (dopo l'aggiornamento dell'SDK) l'app è andata in crash durante l'inizializzazione — il contesto non era ancora disponibile, ma il delegato aveva già eseguito il suo "init".
Storia
Serializzazione errata con delegati: È stato utilizzato un delegato personalizzato per memorizzare i dati, tuttavia conteneva riferimenti non serializzabili al contesto. Durante il tentativo di serializzazione si sono verificate errori e perdita di dati.
Storia
Delegato Observable con errore di callback: Uno sviluppatore ha utilizzato Delegates.observable per controllare lo stato, all'interno della lambda è stato assegnato un nuovo valore, il che ha portato a un ciclo infinito e a StackOverflowError a runtime.