我们可以在 kotlin 中访问任何 属性 的 PropertyMetaData 吗?
Can we access the PropertyMetaData of any property in kotlin?
kotlin 中有没有办法从 属性 外部访问 PropertyMetaData
?更具体地说,来自代表团?
寻找这样的东西:
编辑(现在更合适的例子)
class Obj(var name : String = "")
class Bar {
val prop1 : Obj by Inject.inject() // <- can inject() access prop1 without passing it explicitly?
val prop2 : Obj by Inject.inject()
}
object Inject {
val injected = arrayListOf<ReadOnlyProperty<Any, Obj>>()
fun inject() : ReadOnlyProperty<Any, Obj> {
val delegate = Delegates.lazy {
Obj("NEED THE DELEGATED PROPERTY'S NAME HERE") // <- like "prop1" "prop2" ...
}
injected.add(delegate)
return delegate
}
}
编辑(1.0.0-beta-1038 之后)
此代码片段之前非常有效(注意:使用以前版本的 kotlin 时未显式传递字符串 "scrollPlace",因为之前传递了 属性 名称 "implicitly" ):
val scrollPlace by injectBy<Image>("scrollPlace").replaceBy {
val scrollPane = ScrollPane(VerticalGroup().space(12f).center())
scrollPane.setPosition(it.x, it.y)
scrollPane.setSize(it.width, it.height)
scrollPane
}
在这个例子中,我使用了一些链接。已接受答案的扩展函数 injectBy(基于 1 下建议的模式,传递自定义字符串除外)创建一个 O2dInjectionClosure (ReadOnlyProperty) 实例。解决方案 1) 当然可行,尽管它不如使用 属性Delgated 方便,但链接会造成一些麻烦。至少我还没有想到合适的解决方案。扩展函数 replaceBy 创建另一个新的 O2dInjectionClosure 实例:
public final fun <T : Actor, R : Actor> O2dInjectionClosure<T>.replaceBy(replacer : (replaced : T) -> R) : O2dInjectionClosure<R> {
val originalInitializer = this.initializer
return O2dInjectionClosure { propName ->
... some transferring of the previous O2dInjectionClosure to this one
new
}
}
因此,我想以某种方式在链接的最后一次调用时做一些必要的事情,但要以一种方便的方式:)。
我希望它在某种程度上是合理的
显然您需要在 属性 的委托对象上调用一些初始化代码。有几种解决方法:
1) 使用 属性 引用表达式,如 bashor 所述,获取 属性 的名称并将其传递给 inject
:
val prop1: Obj by Inject.inject(Bar::prop1.name)
val prop2: Obj by Inject.inject(Bar::prop2.name)
虽然很明确,但有点冗长且容易出错。
2) 在第一次访问 属性 时执行初始化逻辑。所以 Inject
本身变成了 属性 委托,维护注册属性的映射。但是,语义上有细微的变化可能不适用于您的用例:要在 Inject
.
中注册 属性 至少需要一个 get
class Bar {
val prop1: Obj by Inject
val prop2: Obj by Inject
}
object Inject {
val injected = hashMapOf<String, ReadOnlyProperty<Any, Obj>>()
fun get(obj: Any, metadata: PropertyMetadata): Obj {
// getOrPut computes and stores the value for the key if it's not present in the map
val property = injected.getOrPut(metadata.name) {
Delegates.lazy {
Obj(metadata.name)
}
}
return property[obj, metadata]
}
}
3)(UPD:不再支持此方法。)使用 propertyDelegated
方法,该方法是 隐藏和实验性 功能,允许您 属性委托用 属性 的元数据初始化,它将在访问时使用此委托。请注意,此方法可能会在 Kotlin 的未来版本中被重命名、重新设计甚至删除。
class Bar {
val prop1: Obj by Inject
val prop2: Obj by Inject
}
object Inject {
val injected = hashMapOf<String, ReadOnlyProperty<Any, Obj>>()
// Experimental method recognized and called by Kotlin on delegated property initialization
fun propertyDelegated(metadata: PropertyMetadata) {
injected[metadata.name] = Delegates.lazy {
Obj(metadata.name)
}
}
fun get(obj: Any, metadata: PropertyMetadata): Obj {
return injected[metadata.name]!!.get(obj, metadata)
}
}
kotlin 中有没有办法从 属性 外部访问 PropertyMetaData
?更具体地说,来自代表团?
寻找这样的东西:
编辑(现在更合适的例子)
class Obj(var name : String = "")
class Bar {
val prop1 : Obj by Inject.inject() // <- can inject() access prop1 without passing it explicitly?
val prop2 : Obj by Inject.inject()
}
object Inject {
val injected = arrayListOf<ReadOnlyProperty<Any, Obj>>()
fun inject() : ReadOnlyProperty<Any, Obj> {
val delegate = Delegates.lazy {
Obj("NEED THE DELEGATED PROPERTY'S NAME HERE") // <- like "prop1" "prop2" ...
}
injected.add(delegate)
return delegate
}
}
编辑(1.0.0-beta-1038 之后)
此代码片段之前非常有效(注意:使用以前版本的 kotlin 时未显式传递字符串 "scrollPlace",因为之前传递了 属性 名称 "implicitly" ):
val scrollPlace by injectBy<Image>("scrollPlace").replaceBy {
val scrollPane = ScrollPane(VerticalGroup().space(12f).center())
scrollPane.setPosition(it.x, it.y)
scrollPane.setSize(it.width, it.height)
scrollPane
}
在这个例子中,我使用了一些链接。已接受答案的扩展函数 injectBy(基于 1 下建议的模式,传递自定义字符串除外)创建一个 O2dInjectionClosure (ReadOnlyProperty) 实例。解决方案 1) 当然可行,尽管它不如使用 属性Delgated 方便,但链接会造成一些麻烦。至少我还没有想到合适的解决方案。扩展函数 replaceBy 创建另一个新的 O2dInjectionClosure 实例:
public final fun <T : Actor, R : Actor> O2dInjectionClosure<T>.replaceBy(replacer : (replaced : T) -> R) : O2dInjectionClosure<R> {
val originalInitializer = this.initializer
return O2dInjectionClosure { propName ->
... some transferring of the previous O2dInjectionClosure to this one
new
}
}
因此,我想以某种方式在链接的最后一次调用时做一些必要的事情,但要以一种方便的方式:)。 我希望它在某种程度上是合理的
显然您需要在 属性 的委托对象上调用一些初始化代码。有几种解决方法:
1) 使用 属性 引用表达式,如 bashor 所述,获取 属性 的名称并将其传递给 inject
:
val prop1: Obj by Inject.inject(Bar::prop1.name)
val prop2: Obj by Inject.inject(Bar::prop2.name)
虽然很明确,但有点冗长且容易出错。
2) 在第一次访问 属性 时执行初始化逻辑。所以 Inject
本身变成了 属性 委托,维护注册属性的映射。但是,语义上有细微的变化可能不适用于您的用例:要在 Inject
.
get
class Bar {
val prop1: Obj by Inject
val prop2: Obj by Inject
}
object Inject {
val injected = hashMapOf<String, ReadOnlyProperty<Any, Obj>>()
fun get(obj: Any, metadata: PropertyMetadata): Obj {
// getOrPut computes and stores the value for the key if it's not present in the map
val property = injected.getOrPut(metadata.name) {
Delegates.lazy {
Obj(metadata.name)
}
}
return property[obj, metadata]
}
}
3)(UPD:不再支持此方法。)使用 propertyDelegated
方法,该方法是 隐藏和实验性 功能,允许您 属性委托用 属性 的元数据初始化,它将在访问时使用此委托。请注意,此方法可能会在 Kotlin 的未来版本中被重命名、重新设计甚至删除。
class Bar {
val prop1: Obj by Inject
val prop2: Obj by Inject
}
object Inject {
val injected = hashMapOf<String, ReadOnlyProperty<Any, Obj>>()
// Experimental method recognized and called by Kotlin on delegated property initialization
fun propertyDelegated(metadata: PropertyMetadata) {
injected[metadata.name] = Delegates.lazy {
Obj(metadata.name)
}
}
fun get(obj: Any, metadata: PropertyMetadata): Obj {
return injected[metadata.name]!!.get(obj, metadata)
}
}