调用静态方法只能访问包含对象的类型
Invoke static method with access only to the containing object's type
我有几个对象之一的 TypeTag
,我知道它们扩展了一个具有已知方法签名的基本特征。如果需要,我还可以访问该方法的 MethodSymbol
。我想做的是:
def invokeMyMethod[T: TypeTag](myMethodSymbol: MethodSymbol): String = {
// I know T has structural type { def myMethod: String }
// so I want the result of calling T.myMethod but I don't have
// access to the actual object T, only its type.
}
因为我知道该类型代表一个对象,所以我知道该方法是静态的,所以我只需要访问单例实例就可以调用该方法。不幸的是,我找不到从类型到实例的方法。
我知道我可以从 runtimeMirror
获得一个 RuntimeClass
实例,但我不确定在获得它后如何处理 class。它似乎本质上具有 AnyRef
类型,所以我尝试投射它但没有成功:
def invokeMyMethod[T: TypeTag]: Any = {
val runtimeT = runtimeMirror(getClass.getClassLoader).runtimeClass(T)
runtimeT.asInstanceOf[{ def myMethod: String }].myMethod
// Error invoking method 'myMethod'
}
我也知道我可以从我的 ClassSymbol
中得到一个 ClassMirror
但这似乎只能访问构造函数 MethodMirror
如果我的项目是一个对象则这无济于事而不是 class:
def invokeMyMethod[T: TypeTag](myMethodSymbol: MethodSymbol): Any = {
val mirror = runtimeMirror(getClass.getClassLoader)
val runtimeT = mirror.runtimeClass(T)
val mirrorT = mirror.reflect(runtimeT)
mirrorT.reflectMethod(myMethodSymbol)()
// Expected a member of class Class, you provided value T.myMethod
}
而且我知道如果我有 T
的实际运行时实例,使用 InstanceMirror
会很容易,但我不知道如何获得我的 InstanceMirror
对象类型。
尝试
import scala.reflect.runtime.universe._
import scala.reflect.runtime
trait BaseTrait {
def myMethod: String
}
object MyObject extends BaseTrait {
override def myMethod: String = "MyObject.myMethod"
}
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val moduleSymbol = typ.termSymbol.asModule
val methodSymbol = typ.decl(TermName("myMethod")).asMethod
val runtimeMirror = runtime.currentMirror
val moduleMirror = runtimeMirror.reflectModule(moduleSymbol)
val instance = moduleMirror.instance
val instanceMirror = runtimeMirror.reflect(instance)
val methodMirror = instanceMirror.reflectMethod(methodSymbol)
methodMirror().asInstanceOf[String]
}
invokeMyMethod[MyObject.type] // MyObject.myMethod
如果对象嵌套成class试试
class Outer {
object `_` extends BaseTrait {
override def myMethod: String = "_.myMethod"
}
}
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val runtimeMirror = runtime.currentMirror
val moduleSymbol = typ.termSymbol.asModule
val outerClassSymbol = moduleSymbol.owner.asClass
val outerClassType = outerClassSymbol.typeSignature
val outerConstructorSymbol = outerClassType.decl(termNames.CONSTRUCTOR).asMethod
val outerClassMirror = runtimeMirror.reflectClass(outerClassSymbol)
val outerConstructorMirror = outerClassMirror.reflectConstructor(outerConstructorSymbol)
val outerInstance = outerConstructorMirror() // if class Outer has no-arg constructor
val outerInstanceMirror = runtimeMirror.reflect(outerInstance)
val moduleMirror = outerInstanceMirror.reflectModule(moduleSymbol)
val methodSymbol = typ.decl(TermName("myMethod")).asMethod
val instance = moduleMirror.instance
val instanceMirror = runtimeMirror.reflect(instance)
val methodMirror = instanceMirror.reflectMethod(methodSymbol)
methodMirror().asInstanceOf[String]
}
val outer = new Outer
invokeMyMethod[outer.`_`.type] // _.myMethod
如果 Outer
是特征(抽象 class)而不是 class,您可以使用工具箱
trait Outer {
object `_` extends BaseTrait {
override def myMethod: String = "_.myMethod"
}
}
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val runtimeMirror = runtime.currentMirror
val toolbox = runtimeMirror.mkToolBox()
val outerClassSymbol = toolbox.define(
q"class OuterImpl extends com.example.Outer".asInstanceOf[ClassDef]
).asClass
toolbox.eval(q"(new $outerClassSymbol).`_`.myMethod").asInstanceOf[String]
}
val outer = new Outer {}
invokeMyMethod[outer.`_`.type] // _.myMethod
或
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val runtimeMirror = runtime.currentMirror
val toolbox = runtimeMirror.mkToolBox()
val toolboxMirror = toolbox.mirror
val moduleSymbol = typ.termSymbol.asModule
val outerClassSymbol = toolbox.define(
q"class OuterImpl extends com.example.Outer".asInstanceOf[ClassDef]
).asClass
val outerClassType = outerClassSymbol.typeSignature
val outerConstructorSymbol = outerClassType.decl(termNames.CONSTRUCTOR).asMethod
val outerClassMirror = toolboxMirror.reflectClass(outerClassSymbol)
val outerConstructorMirror = outerClassMirror.reflectConstructor(outerConstructorSymbol)
val outerInstance = outerConstructorMirror()
val outerInstanceMirror = runtimeMirror.reflect(outerInstance)
val moduleMirror = outerInstanceMirror.reflectModule(moduleSymbol)
val methodSymbol = typ.decl(TermName("myMethod")).asMethod
val instance = moduleMirror.instance
val instanceMirror = toolboxMirror.reflect(instance)
val methodMirror = instanceMirror.reflectMethod(methodSymbol)
methodMirror().asInstanceOf[String]
}
val outer = new Outer {}
invokeMyMethod[outer.`_`.type] // _.myMethod
或者如果你可以使用现有的外部实例class/trait试试
val outer = new Outer
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val runtimeMirror = runtime.currentMirror
val moduleSymbol = typ.termSymbol.asModule
val outerInstanceMirror = runtimeMirror.reflect(outer)
val moduleMirror = outerInstanceMirror.reflectModule(moduleSymbol)
val methodSymbol = typ.decl(TermName("myMethod")).asMethod
val instance = moduleMirror.instance
val instanceMirror = runtimeMirror.reflect(instance)
val methodMirror = instanceMirror.reflectMethod(methodSymbol)
methodMirror().asInstanceOf[String]
}
invokeMyMethod[outer.`_`.type] // _.myMethod
其实可以用outer
解构输入类型
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val outerSymbol = typ match {
case SingleType(pre, _) => pre.termSymbol
}
val runtimeMirror = runtime.currentMirror
val toolbox = runtimeMirror.mkToolBox()
toolbox.eval(q"$outerSymbol.`_`.myMethod").asInstanceOf[String]
}
val outer = new Outer
invokeMyMethod[outer.`_`.type] // _.myMethod
我有几个对象之一的 TypeTag
,我知道它们扩展了一个具有已知方法签名的基本特征。如果需要,我还可以访问该方法的 MethodSymbol
。我想做的是:
def invokeMyMethod[T: TypeTag](myMethodSymbol: MethodSymbol): String = {
// I know T has structural type { def myMethod: String }
// so I want the result of calling T.myMethod but I don't have
// access to the actual object T, only its type.
}
因为我知道该类型代表一个对象,所以我知道该方法是静态的,所以我只需要访问单例实例就可以调用该方法。不幸的是,我找不到从类型到实例的方法。
我知道我可以从 runtimeMirror
获得一个 RuntimeClass
实例,但我不确定在获得它后如何处理 class。它似乎本质上具有 AnyRef
类型,所以我尝试投射它但没有成功:
def invokeMyMethod[T: TypeTag]: Any = {
val runtimeT = runtimeMirror(getClass.getClassLoader).runtimeClass(T)
runtimeT.asInstanceOf[{ def myMethod: String }].myMethod
// Error invoking method 'myMethod'
}
我也知道我可以从我的 ClassSymbol
中得到一个 ClassMirror
但这似乎只能访问构造函数 MethodMirror
如果我的项目是一个对象则这无济于事而不是 class:
def invokeMyMethod[T: TypeTag](myMethodSymbol: MethodSymbol): Any = {
val mirror = runtimeMirror(getClass.getClassLoader)
val runtimeT = mirror.runtimeClass(T)
val mirrorT = mirror.reflect(runtimeT)
mirrorT.reflectMethod(myMethodSymbol)()
// Expected a member of class Class, you provided value T.myMethod
}
而且我知道如果我有 T
的实际运行时实例,使用 InstanceMirror
会很容易,但我不知道如何获得我的 InstanceMirror
对象类型。
尝试
import scala.reflect.runtime.universe._
import scala.reflect.runtime
trait BaseTrait {
def myMethod: String
}
object MyObject extends BaseTrait {
override def myMethod: String = "MyObject.myMethod"
}
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val moduleSymbol = typ.termSymbol.asModule
val methodSymbol = typ.decl(TermName("myMethod")).asMethod
val runtimeMirror = runtime.currentMirror
val moduleMirror = runtimeMirror.reflectModule(moduleSymbol)
val instance = moduleMirror.instance
val instanceMirror = runtimeMirror.reflect(instance)
val methodMirror = instanceMirror.reflectMethod(methodSymbol)
methodMirror().asInstanceOf[String]
}
invokeMyMethod[MyObject.type] // MyObject.myMethod
如果对象嵌套成class试试
class Outer {
object `_` extends BaseTrait {
override def myMethod: String = "_.myMethod"
}
}
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val runtimeMirror = runtime.currentMirror
val moduleSymbol = typ.termSymbol.asModule
val outerClassSymbol = moduleSymbol.owner.asClass
val outerClassType = outerClassSymbol.typeSignature
val outerConstructorSymbol = outerClassType.decl(termNames.CONSTRUCTOR).asMethod
val outerClassMirror = runtimeMirror.reflectClass(outerClassSymbol)
val outerConstructorMirror = outerClassMirror.reflectConstructor(outerConstructorSymbol)
val outerInstance = outerConstructorMirror() // if class Outer has no-arg constructor
val outerInstanceMirror = runtimeMirror.reflect(outerInstance)
val moduleMirror = outerInstanceMirror.reflectModule(moduleSymbol)
val methodSymbol = typ.decl(TermName("myMethod")).asMethod
val instance = moduleMirror.instance
val instanceMirror = runtimeMirror.reflect(instance)
val methodMirror = instanceMirror.reflectMethod(methodSymbol)
methodMirror().asInstanceOf[String]
}
val outer = new Outer
invokeMyMethod[outer.`_`.type] // _.myMethod
如果 Outer
是特征(抽象 class)而不是 class,您可以使用工具箱
trait Outer {
object `_` extends BaseTrait {
override def myMethod: String = "_.myMethod"
}
}
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val runtimeMirror = runtime.currentMirror
val toolbox = runtimeMirror.mkToolBox()
val outerClassSymbol = toolbox.define(
q"class OuterImpl extends com.example.Outer".asInstanceOf[ClassDef]
).asClass
toolbox.eval(q"(new $outerClassSymbol).`_`.myMethod").asInstanceOf[String]
}
val outer = new Outer {}
invokeMyMethod[outer.`_`.type] // _.myMethod
或
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val runtimeMirror = runtime.currentMirror
val toolbox = runtimeMirror.mkToolBox()
val toolboxMirror = toolbox.mirror
val moduleSymbol = typ.termSymbol.asModule
val outerClassSymbol = toolbox.define(
q"class OuterImpl extends com.example.Outer".asInstanceOf[ClassDef]
).asClass
val outerClassType = outerClassSymbol.typeSignature
val outerConstructorSymbol = outerClassType.decl(termNames.CONSTRUCTOR).asMethod
val outerClassMirror = toolboxMirror.reflectClass(outerClassSymbol)
val outerConstructorMirror = outerClassMirror.reflectConstructor(outerConstructorSymbol)
val outerInstance = outerConstructorMirror()
val outerInstanceMirror = runtimeMirror.reflect(outerInstance)
val moduleMirror = outerInstanceMirror.reflectModule(moduleSymbol)
val methodSymbol = typ.decl(TermName("myMethod")).asMethod
val instance = moduleMirror.instance
val instanceMirror = toolboxMirror.reflect(instance)
val methodMirror = instanceMirror.reflectMethod(methodSymbol)
methodMirror().asInstanceOf[String]
}
val outer = new Outer {}
invokeMyMethod[outer.`_`.type] // _.myMethod
或者如果你可以使用现有的外部实例class/trait试试
val outer = new Outer
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val runtimeMirror = runtime.currentMirror
val moduleSymbol = typ.termSymbol.asModule
val outerInstanceMirror = runtimeMirror.reflect(outer)
val moduleMirror = outerInstanceMirror.reflectModule(moduleSymbol)
val methodSymbol = typ.decl(TermName("myMethod")).asMethod
val instance = moduleMirror.instance
val instanceMirror = runtimeMirror.reflect(instance)
val methodMirror = instanceMirror.reflectMethod(methodSymbol)
methodMirror().asInstanceOf[String]
}
invokeMyMethod[outer.`_`.type] // _.myMethod
其实可以用outer
解构输入类型
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val outerSymbol = typ match {
case SingleType(pre, _) => pre.termSymbol
}
val runtimeMirror = runtime.currentMirror
val toolbox = runtimeMirror.mkToolBox()
toolbox.eval(q"$outerSymbol.`_`.myMethod").asInstanceOf[String]
}
val outer = new Outer
invokeMyMethod[outer.`_`.type] // _.myMethod