Kotlin: ¿cómo hacer una propiedad delegada por map con un nombre personalizado?

Estoy tratando de entender a los delegates de propiedad, y tengo un caso de uso interesante. ¿Es posible tener algo como esto?

class MyClass { val properties = mutableMapOf<String, Any>() val fontSize: Any by MapDelegate(properties, "font-size") } 

Eso me permitiría almacenar fontSize utilizando el map como un delegado, pero con una key personalizada (es decir, "tamaño de fuente").

El caso de uso específico es para almacenar cosas como tags de propiedad CSS a las que se puede acceder mediante variables ( fontSize ) para usarlas en el código, pero que se pueden representar de forma adecuada al recorrer el map ( font-size: 18px; ).

La documentation sobre las properties delegadas es una buena fuente de información sobre el tema. Probablemente es un poco más leída que los siguientes ejemplos:

 fun <T, TValue> T.map(properties: MutableMap<String, TValue>, key: String): ReadOnlyProperty<T, TValue> { return object : ReadOnlyProperty<T, TValue> { override fun getValue(thisRef: T, property: KProperty<*>) = properties[key]!! } } class MyClass { val properties = mutableMapOf<String, Any>() val fontSize: Any by map(properties, "font-size") } 

Puede facilitar un poco las cosas y evitar escribir el nombre de propiedad de CSS convirtiendo los nombres de propiedad de Kotlin en equivalentes de attributes de CSS como los siguientes:

 fun <T, TValue> map(properties: Map<String, TValue>, naming:(String)->String): ReadOnlyProperty<T, TValue?> { return object : ReadOnlyProperty<T, TValue?> { override fun getValue(thisRef: T, property: KProperty<*>) = properties[naming(property.name)] } } object CamelToHyphen : (String)->String { override fun invoke(camelCase: String): String { return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, camelCase) } } fun <T, TValue> T.cssProperties(properties: Map<String,TValue>) = map(properties, CamelToHyphen) class MyClass { val properties = mutableMapOf<String, Any>() val fontSize: Any? by cssProperties(properties) } 

La muestra anterior usa el CaseFormat de Guava.

Si desea tener propiedad mutable, su delegado deberá implementar el método setter:

 fun <T, TValue> map(properties: MutableMap<String, TValue?>, naming: (String) -> String): ReadWriteProperty<T, TValue?> { return object : ReadWriteProperty<T, TValue?> { override fun setValue(thisRef: T, property: KProperty<*>, value: TValue?) { properties[naming(property.name)] = value } override fun getValue(thisRef: T, property: KProperty<*>) = properties[naming(property.name)] } } 
  • Crear un propio DataSource con properties de resorte
  • Kotlin - Inicialización de propiedad usando "por perezoso" vs. "tardío"
  • Función de extensión Kotlin en propiedad mutable
  • ¿Por qué el código que inicializa una propiedad de interfaz variable no se codificará en la compilation del bloque init?
  • ¿Cuál es la forma más sencilla de get propiedad segura para subprocesss en Kotlin?
  • Propiedad observable que permite agregar observadores en time de ejecución
  • Propiedad protegida abstracta Kotlin
  • Obtención de información de KProperty dentro de la propiedad delegada fuera de las funciones getValue () y setValue ()
  • Property setter con diferente tipo
  • Kotlin getter setter sin campo
  • ¿Cómo implementar una propiedad que proviene de una fuente determinada hasta que se establece directamente en Kotlin?