Kotlin委托属性实现'provideDelegate'操作符函数,但方法从未调用过

我有一个基本类型DbType这是扩展我的模型是这样的:

 interface DbType { fun <T : Any> field() = PropertyMapper<T>() } 

PropertyMapper类是这样实现的:

 class PropertyMapper<out T : Any> internal constructor() { @Suppress("UNCHECKED_CAST") operator fun getValue(inst: DbType, prop: KProperty<*>): T { return ImplementationDetail.values?.get(prop.name) as T? ?: throw NullPointerException("No such ${prop.name} in type ${inst::class}") } operator fun provideDelegate(inst: DbType, prop: KProperty<*>): ReadOnlyProperty<DbType, T> { TODO() } } 

根据kotlin文档中的这个条目,我应该能够通过在属性委托给的类中添加一个运算符函数provideDelegate来提供自己的ReadOnlyProperty<R, T> 。 但是,当我实例化一个实现/扩展DbType的对象时,运算符函数provideDelegate从不被调用。 “getValue”部分工作正常,但我想拦截创建对象时的属性委托创建。 任何想法我做错了吗? 这是一个示例类:

 class BasicUserInfo : DbType { val username by field<String>() } 

你确定它没有被叫? 我在你的代码中发现错误的是,当你实现了provideDelegate运算符,并返回一些委托对象,而不是它的接收者,你不需要getValue操作符来实现,因为它不会被使用,它的对象provideDelegate返回将用于属性访问(见下文)。

否则,你的代码是有效的。 我稍微修改了你的例子,使其更清楚发生了什么:

 class PropertyMapper<out T : Any> internal constructor() { operator fun getValue(inst: DbType, prop: KProperty<*>): T { println("PropertyMapper :: getValue") // note: never printed TODO() } operator fun provideDelegate(inst: DbType, prop: KProperty<*>): ReadOnlyProperty<DbType, T> { println("PropertyMapper :: provideDelegate") return object : ReadOnlyProperty<DbType, T> { override fun getValue(thisRef: DbType, property: KProperty<*>): T { println("anonymous ReadOnlyProperty :: getValue") TODO() } } } } 

DbTypeBasicUserInfo保持不变。

现在,当我创建一个BasicUserInfo实例并获取其username (使用表达式BasicUserInfo().username )时,我得到以下输出:

 PropertyMapper :: provideDelegate anonymous ReadOnlyProperty :: getValue Exception in thread "main" kotlin.NotImplementedError: An operation is not implemented. ... 

如果我只创建实例,那只是第一行。

请参阅此代码的可运行演示 。

我想通了:这似乎是在kotlin插件或gradle中的错误。 如果我使用PropertyMapper构建一个干净的项目,只有一个名为getValue运算符方法,它将按预期工作:在访问该字段时调用PropertyMapper#getValue

然后,当我删除该方法,而是使用provideDelegate运算符方法,它会失败,一个NoSuchMethodError (永远不会调用PropertyMapper#provideDelegate方法)。 如果我清理(手动删除构建/出文件夹)并重新构建该设置,它运行得很好。