【问题标题】:Kotlin delegate properties implementing 'provideDelegate' operator function, but method never calledKotlin 委托属性实现“provideDelegate”运算符函数,但从未调用过方法
【发布时间】:2017-08-06 22:04:56
【问题描述】:

我有一个基本类型 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 文档中的this 条目,我应该能够通过在属性委托给的类中添加运算符函数provideDelegate 来提供我自己的ReadOnlyProperty&lt;R, T&gt;。但是,当我实例化一个实现/扩展DbType 的对象时,永远不会调用运算符函数provideDelegate。 “getValue”部分工作正常,但我想在创建对象时拦截属性委托创建。知道我做错了什么吗?这是一个示例类:

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

【问题讨论】:

    标签: java delegates jvm kotlin


    【解决方案1】:

    你确定它没有被调用吗?我在您的代码中发现错误的是,当您实现 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.
    ...
    

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

    请参阅the runnable demo of this code

    【讨论】:

    • 我正在运行的 kotlin 版本或可能是 gradle 插件(不是为 android 编程 - 仅使用 kotlin 和 java 插件)肯定有问题。当我从您的演示中的PropertyMapper 类中删除getValue 方法时,它仍然可以正常工作,正如预期的那样(即仅在ReadOnlyProperty 返回的PropertyMapper#provideDelegate 实例中的getValue 方法中的TODO() 失败. 但是,当我在我的项目中的机器上运行它时,它在尝试访问该属性时失败并显示NoSuchMethodError
    • Here's an example(我修改了你的)这更类似于我正在尝试做的事情和here's the repository,更具体地说:interfaceimplementation
    • 将我的评论移至答案 - 请参阅下面的解释。如果我可以在一个孤立的示例中一致地重现,我将提交错误报告
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-28
      • 2011-08-12
      相关资源
      最近更新 更多