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)] } } 
  • ¿Por qué el código que inicializa una propiedad de interfaz variable no se codificará en la compilation del bloque init?
  • Función de extensión Kotlin en propiedad mutable
  • Convierta variables estáticas de Java a Kotlin
  • ¿Hay un análogo didSet / willSet en Kotlin?
  • Propiedad protegida abstracta Kotlin
  • Kotlin: ¿Cómo puedo usar properties delegadas en Java?
  • Obtención de información de KProperty dentro de la propiedad delegada fuera de las funciones getValue () y setValue ()
  • Kotlin: ¿Cómo puedo get la class de delegación de una propiedad miembro?
  • Crear un propio DataSource con properties de resorte
  • ¿Cuál es la forma más sencilla de get propiedad segura para subprocesss en Kotlin?
  • Alias ​​en línea para la function de Kotlin que incluye generics