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”,因为之前是“隐式”传递了属性名):
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)当然可以工作,即使它不像使用propertyDelgated那样方便,但是链接会带来一些麻烦。至少我还没有想到适当的解决方案。扩展函数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
    }
}

因此,我想以某种方便的方式在链的最后一次调用中做必要的事情:)。
我希望这是合理的

最佳答案

显然,您需要在属性的委托(delegate)对象上调用一些初始化代码。有几种解决方案:

1)使用bashor指出的属性引用表达式来获取属性的名称,并将其传递给inject:

val prop1: Obj by Inject.inject(Bar::prop1.name)
val prop2: Obj by Inject.inject(Bar::prop2.name)

尽管很明显,但这是一种冗长且容易出错的方法。

2)在首次访问属性时执行初始化逻辑。因此Inject本身成为属性委托(delegate),维护已注册属性的映射。但是,语义上的微小变化可能不适用于您的用例:要在get中注册该属性,至少需要一个Inject
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方法是一种隐藏的实验性功能,它允许使用属性的元数据初始化属性委托(delegate),该属性的元数据将在访问时使用该委托(delegate)。请注意,在将来的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)
    }
}

07-24 19:19
查看更多