I would like to make the properties of a class and it's child classes available at runtime for read and write via by integer id or by the name of the property with performance as close to that of a regular compiled read or write as feasible. There may be many instances of the this class and it's child classes (say up to 1 million) and each class may have hundreds of properties, so I want to minimise the memory used by each property in each class instance.
The broad solution groups that I see are using reflection, making each property an instance of a mutable class and then keeping maps of these, or writing giant when statements.
I've tested the performance of a reflection implementation (see below). This takes 15 times as long as directly accessing the property in my test.
Can this be improved, or is there better way to do this?
class ReflectionClass {
@FieldId(1)
var intField = 0
fun getPropById(id: Int): Any? {
val property = propertiesById[id]
return property?.get(this)
}
fun setIntPropById(id: Int, value: Int) {
val property = propertiesById[id]
if (property is KMutableProperty1) {
property?.setter?.call(this, value)
}
}
fun getPropByName(name: String): Any? {
val property = propertiesByName[name]
return property?.get(this)
}
fun setIntPropByName(name: String, value: Int) {
val property = propertiesByName[name]
if (property is KMutableProperty1) {
property as KMutableProperty1<ReflectionClass, Int>
property.set(this, value)
}
}
companion object {
//private val propertiesById = HashMap<Int, KProperty1<ReflectionClass,*>>()
private val propertiesById = HashMap<Int, KProperty1<ReflectionClass, *>?>()
private val propertiesByName = HashMap<String, KProperty1<ReflectionClass, *>>()
init {
val fields = ReflectionClass::class.memberProperties.forEach { property ->
val id = property.findAnnotation<FieldId>()
if (id != null) {
propertiesById.put(id.id, property)
propertiesByName.put(property.name, property)
}
}
}
}
}