前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kotlin之提供委托

Kotlin之提供委托

作者头像
xiangzhihong
发布2018-02-08 10:07:17
1.4K0
发布2018-02-08 10:07:17
举报
文章被收录于专栏:向治洪向治洪

通过定义 provideDelegate 操作符,可以扩展创建属性实现所委托对象的逻辑。 如果 by 右侧所使用的对象将 provideDelegate 定义为成员或扩展函数,那么会调用该函数来 创建属性委托实例。

provideDelegate 的一个可能的使用场景是在创建属性时(而不仅在其 getter 或 setter 中)检查属性一致性。例如,如果要在绑定之前检查属性名称,可以这样写:

代码语言:javascript
复制
class ResourceLoader<T>(id: ResourceID<T>) {
    operator fun provideDelegate(
            thisRef: MyUI,
            prop: KProperty<*>
    ): ReadOnlyProperty<MyUI, T> {
        checkProperty(thisRef, prop.name)
        // 创建委托
    }

    private fun checkProperty(thisRef: MyUI, name: String) { …… }
}

fun <T> bindResource(id: ResourceID<T>): ResourceLoader<T> { …… }

class MyUI {
    val image by bindResource(ResourceID.image_id)
    val text by bindResource(ResourceID.text_id)
}

provideDelegate 的参数与 getValue 相同:

  • thisRef —— 必须与 属性所有者 类型(对于扩展属性——指被扩展的类型)相同或者是它的超类型。
  • property —— 必须是类型 KProperty<*> 或其超类型。 在创建 MyUI 实例期间,为每个属性调用provideDelegate 方法,并立即执行必要的验证。

如果没有这种拦截属性与其委托之间的绑定的能力,为了实现相同的功能, 你必须显式传递属性名,这不是很方便:

代码语言:javascript
复制
// 检查属性名称而不使用“provideDelegate”功能
class MyUI {
    val image by bindResource(ResourceID.image_id, "image")
    val text by bindResource(ResourceID.text_id, "text")
}

fun <T> MyUI.bindResource(
        id: ResourceID<T>,
        propertyName: String
): ReadOnlyProperty<MyUI, T> {
   checkProperty(this, propertyName)
   // 创建委托
}

在生成的代码中,会调用 provideDelegate 方法来初始化辅助的 prop$delegate 属性。 比较对于属性声明 val prop: Type by MyDelegate() 生成的代码与 上面(当 provideDelegate 方法不存在时)生成的代码:

代码语言:javascript
复制
class C {
    var prop: Type by MyDelegate()
}

// 这段代码是当“provideDelegate”功能可用时,由编译器生成的代码:
class C {
    // 调用“provideDelegate”来创建额外的“delegate”属性
    private val prop$delegate = MyDelegate().provideDelegate(this, this::prop)
    val prop: Type
        get() = prop$delegate.getValue(this, this::prop)
}

请注意,provideDelegate 方法只影响辅助属性的创建,并不会影响为 getter 或 setter 生成的代码。

上面例子的完整代码为:

代码语言:javascript
复制
fun main(args: Array<String>) {
    val myui: MyUI = MyUI()
    println(myui.image)
}

class dge<T>(t: T) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, 这里委托了 ${property.name} 属性"
    }
}

class ResourceLoader<T>(id: Int) {
    operator fun provideDelegate(
            thisRef: MyUI,
            prop: KProperty<*>
    ): dge<T?> {
        checkProperty(thisRef, prop.name)
        // 创建委托
        var t: T? = null
        return dge(t)
    }

    private fun checkProperty(thisRef: MyUI, name: String) {
        println(name)
    }
}

fun <T> bindResource(id: Int): ResourceLoader<T> {
    return ResourceLoader<T>(id)
}

class MyUI {
    val image by bindResource<String>(1)
    val text by bindResource<String>(2)
}  
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-12-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档