Kotlin中protected成员扩展的with调用失效问题及解决办法咨询
Kotlin protected成员扩展方法委托调用失效问题分析与解决
问题场景
在自定义Jetpack Compose的Painter装饰器时,试图通过with(delegate)调用委托对象的onDraw方法,却意外触发了自身的onDraw实现;后续用StringPrinter的示例验证发现,当把抽象扩展方法设为protected后,委托调用完全失效,而public状态下一切正常。
核心原因
Kotlin的成员扩展方法本质上绑定到宿主类,当方法标记为protected时,其可见性被限制在类及子类内部:
- 当在子类中使用
with(delegate)时,代码块上下文虽为delegate实例,但编译器会优先匹配子类自身override的protected扩展方法(因为子类可访问该方法),而非委托对象的实现。 - 若扩展方法是
public,编译器会优先匹配上下文对象(delegate)的实现,因为此时方法可见性是全局的,不会被子类的override覆盖上下文调用。
解决方案
1. 针对自定义Painter场景
Compose的Painter.onDraw是DrawScope的扩展成员方法,直接通过显式传入DrawScope上下文调用委托对象的onDraw即可:
class MyPainter(private val delegate: Painter) : Painter() { override fun DrawScope.onDraw() { // 直接传入当前DrawScope,调用委托对象的onDraw delegate.onDraw(this) // 后续添加自定义绘制逻辑 drawCircle(Color.Blue, radius = 30f) } override val intrinsicSize: Size get() = delegate.intrinsicSize }
2. 针对StringPrinter类场景
方案一:替换为普通成员方法(推荐)
放弃扩展方法,改用普通成员方法避免作用域混淆:
abstract class StringPrinter { protected abstract fun printString(value: String) fun print(value: String) = printString(value) } class StringConsolePrinter : StringPrinter() { override fun printString(value: String) { println(value) } } class StringBackwardsPrinter(private val delegate: StringPrinter) : StringPrinter() { override fun printString(value: String) { delegate.printString(value.reversed()) } }
方案二:显式指定扩展方法的宿主对象
若必须保留扩展方法,可通过Kotlin成员扩展方法的编译本质(静态方法,第一个参数为宿主实例)显式调用:
class StringBackwardsPrinter(private val delegate: StringPrinter) : StringPrinter() { override fun String.getPrinted() { // 显式指定宿主为delegate,调用其扩展方法 delegate.run { reversed().getPrinted() } } }
内容的提问来源于stack exchange,提问作者Jezor
相关产品推荐
相关产品推荐

