kotlin 上下文参数(在上下文接收器功能中)未通过反射显示

wmtdaxz3  于 2023-03-24  发布在  Kotlin
关注(0)|答案(1)|浏览(201)

通过反射,我需要区分有上下文的方法和没有上下文的方法(Kotlin1.8.0)。
假设我们有下面的虚拟上下文和一个有两个函数的类-一个有上下文,第二个没有。

class Context(val a: Int)

  class Foo {
    context (Context)
    fun bar() = a
    
    fun baz() = 1
  }

在运行时,我们不知道哪个方法是哪个方法,所以让我们尝试通过反射来区分它们。

val foo = Foo()

  val barMethod = foo::class.memberFunctions.first { it.name == "bar" }
  println("barMethod has ${barMethod.parameters.size} parameter(s)")

  val bazMethod = foo::class.memberFunctions.first { it.name == "baz" }
  println("bazMethod has ${bazMethod.parameters.size} parameter(s)")

问题是,两者都返回一个参数(在所有其他公共属性中都是相同的)。但很明显,当调用时,如果只提供一个参数,bar将失败。如果按预期调用,它可以工作。

// println(barMethod.call(foo))        -- fails
  println(bazMethod.call(foo))

  println(barMethod.call(foo, Context(6))

在调试时,我发现barMethod(KCallableImpl)上实际上有一个内部属性descriptor,它包含contextReceiverParameters属性,正确显示barMethod为1,bazMethod为0。但它不可访问。
有什么想法,如果有任何支持的方式通过反射检索上下文接收者的信息,或者它只是还没有实现?

kr98yfug

kr98yfug1#

首先,定义注解类:

@Target(AnnotationTarget.FUNCTION)
annotation class WithContext

然后,用下面的注解来注解具有上下文接收器的函数:

class Context(val a: Int)

class Foo {
    context (Context)
    
    @WithContext
    fun bar() = a
    
    fun baz() = 1
}

现在你可以使用下面的代码来检查一个函数是否有上下文接收器:

val foo = Foo()

val barMethod = foo::class.memberFunctions.first { it.name == "bar" }
val hasBarContext = barMethod.annotations.any { it is WithContext }
println("barMethod has context: $hasBarContext")

val bazMethod = foo::class.memberFunctions.first { it.name == "baz" }
val hasBazContext = bazMethod.annotations.any { it is WithContext }
println("bazMethod has context: $hasBazContext")

这将输出:

barMethod has context: true
bazMethod has context: false

请记住,这种方法依赖于手动将**@WithContext**注解添加到具有上下文接收器的函数中。在未来的Kotlin版本中,当功能变得稳定并且反射变得更稳定时,可能会有更直接的方法来访问上下文接收器参数。

相关问题