如何从 AnyRef 对象获取反映的运行时方法?
Posted
技术标签:
【中文标题】如何从 AnyRef 对象获取反映的运行时方法?【英文标题】:How to get reflected runtime Method from AnyRef object? 【发布时间】:2018-08-02 15:19:56 【问题描述】:我正在尝试在实例中获取反射的运行时方法,但它未显示在 decls
结果中:
val foo: AnyRef = new Object
def bar = 1
typeOf[foo.type].decls //Does not contain bar method
我尝试使用 Java 反射类并且它可以工作:
foo.getClass.getDeclaredMethods //It contains bar method
但我更喜欢使用 MethodSymbols 和 Scala 类型而不是 Java 类和方法反射。如何获取反射的 MethodSymbol?
我想要一个方法来查找作为 AnyRef 传递给方法栏的对象并调用它。如下所示:
def getBarMethodFromObj(obj: AnyRef): MethodSymbol =
//typeOf(obj).decl(TermName("bar")) this doesn't work
我不能使用 trait,因为 bar 可以有不同的参数并返回类型和数字。由于 Scala 不支持可变泛型参数,我计划使用反射来查找方法和调用,但这在 Scala 中也无法完成。我目前正在使用Java解决方案:
val bar = foo.getClass.getDeclaredMethods.find(_.getName == "bar")
bar.invoke(foo, params: _*)
但是 Java 反射不保留泛型类型,因为它会给 List 和 Map 等带来问题。所以我想知道我是否可以在 Scala 中实现它,或者是否有任何即将到来的解决方案
【问题讨论】:
请注意foo.bar
也不编译。值foo
的类型为foo.type
,是AnyRef
的子类型,而AnyRef
没有方法bar
。 typeOf[foo.type]
gizmo 只包含在编译时可以推断的信息,而在编译时,从编译器的角度来看,没有任何东西表明foo
有一个方法bar
。
@AndreyTyukin 感谢您的评论。我改成运行时反射方法
TypeTags 对于大多数用例来说已经足够了,我想,但你的用例是什么?
【参考方案1】:
我不知道您要做什么,但是删除 AnyRef
注释可以使您的代码正常工作:
val foo = new def bar = 1
typeOf[foo.type].decls // Contains bar method
如果需要类型注解(例如,在方法签名中),可以使用编译器推断的相同结构类型:
val foo: def bar: Int = new def bar = 1
如果您想从另一个方法中获取完整的方法列表,而不知道确切的类型,除了通过泛型,您可能对TypeTag
感兴趣:
import scala.reflect.runtime.universe. TypeTag, typeTag
val foo = new def bar = 1
def getMethods[T: TypeTag](t: T) = typeTag[T].tpe.decls
getMethods(foo) // Contains bar
如果您不能使用TypeTag
(可能是因为您无法更改 API),那么您最好使用 Java 反射 API。 Scala 反射 API 一般设计为使用类型信息,所以如果你只知道类型是AnyRef
,它可能对你不起作用。
响应您的编辑:
我不能使用 trait,因为 bar 可以有不同的参数并返回类型和数字。
当然可以:
trait Foo[A, B]
def bar(a: A): B
如果您需要多个参数,只需让bar
取一个元组即可。如果你需要做一些元组不支持的列表操作,你可以考虑学习 HLists 和shapeless。
但是 Java 反射不保留泛型类型...
好吧,没有任何仅运行时的反射 API 可以帮助您。根本无法找出AnyRef
在运行时具有哪些通用参数,因为JVM 上不存在该信息。使用 TypeTags,或以上述方式使用trait
。
【讨论】:
在您的示例 3 中,foo 不是 AnyRef,而是声明了 bar 方法的匿名类,因此您可以使用 decls。在我的用例中, foo 是从一个没有已知类型但 AnyRef 的参数传递的,所以 decls 不起作用 @texasbruce 我想通了。我建议更改您的 API 以使用 TypeTags 或结构类型。否则,我认为您会被 Java 反射 API 卡住。 @texasbruce 我已更新我的答案以回应您的编辑。 它实际上并不适合我的需要,因为我想要的方法具有未定义数量的参数(可变参数),但 Scala 不支持泛型 var args 所以我想求助于使用反射。但是当参数类似于 List[Foo] 时,我还需要保留泛型参数。我想这对于 Scala 当前版本来说是不可能完成的任务。我接受了这个答案,因为它提到这是不可能的。以上是关于如何从 AnyRef 对象获取反映的运行时方法?的主要内容,如果未能解决你的问题,请参考以下文章
c++ 如何在运行时获取 COM 对象 Coclass 的 progid