我有这样的课:
trait ThirdParty { def invoke = println("right") }
trait WeatherIcon { def invoke = println("wrong") }
class MyClass {
object objA extends ThirdParty
object objB extends WeatherIcon
}
Run Code Online (Sandbox Code Playgroud)
如何使用Scala反射API迭代包含的对象并调用方法(如果它是ThirdParty类的实例)?
Dan*_*ral 14
根据soc写的,我得到了这个:
import scala.reflect.runtime.universe._
val members = typeOf[MyClass].members.filter(_.typeSignature match {
case tpe if tpe <:< typeOf[ThirdParty] => true
case NullaryMethodType(tpe) if tpe <:< typeOf[ThirdParty] => true
case MethodType(Nil, tpe) if tpe <:< typeOf[ThirdParty] => true
case _ => false
})
Run Code Online (Sandbox Code Playgroud)
让我解释模式匹配.a val或an 的类型object可以直接比较,但函数的类型略有不同.在这里,我将匹配没有参数列表的方法,以及具有零参数列表的方法.
与soc的答案相比,这里有一些差异.首先,我使用members而不是declarations.这将返回继承的成员以及MyClass自身声明的成员.
其次,我检查它是值成员,而不是类型成员.您只能在值上调用方法,因此它看起来是合理的限制,尽管可能没有必要.UPD.该isValue方法在2.10.0-RC1中不再可用,因此我删除了检查.
最后,我使用<:<而不是检查每个父级是否相等.
现在,来调用.我将更改上面的代码,因为调用取决于您拥有的成员类型,因此我们最好同时进行过滤和调用.我会从改变members到nonPrivateMembers还有,假设这是什么都想.UPD.nonPrivateMembers在2.10.0-RC1中不再可用,filter(!_.isPrivate)必要时使用.
而且我也会避免使用typeOf,这对REPL上的镜像无效.UPD.在2.10.0-RC1 typeOf工作正常,但我会保持实现的骨架不变.
以上所有内容基本上都与事物的结构有关:一种类型的成员是什么,他们是什么样的成员,等等.当你想要使用这些东西时,你需要镜子.
每当你有一个符号或类型的东西 - 一个类,一个方法,一个obj等 - 你通过镜子对这个东西采取行动.要(反射地)对象的实例进行操作,您需要一个实例镜像.要对方法执行操作,您需要一个方法镜像,依此类推.
因此,让我们尝试构建一个功能来执行所要求的操作:
import scala.reflect.runtime.universe._
def invoke[Target : TypeTag](obj: Any): Seq[Target] = {
val mirror = runtimeMirror(obj.getClass.getClassLoader)
val insMirror = mirror reflect obj
val originType = insMirror.symbol.typeSignature
val targetType = typeTag[Target].tpe
val members = originType.members
val result = members collect (member => member.typeSignature match {
case tpe if tpe <:< typeOf[ThirdParty] =>
if (member.isModule)
(insMirror reflectModule member.asModule).instance
else
(insMirror reflectField member.asTerm).get
case NullaryMethodType(tpe) if tpe <:< typeOf[ThirdParty] =>
(insMirror reflectMethod member.asMethod).apply()
case MethodType(Nil, tpe) if tpe <:< typeOf[ThirdParty] =>
(insMirror reflectMethod member.asMethod).apply()
})
result.map(_.asInstanceOf[Target]).toSeq
}
Run Code Online (Sandbox Code Playgroud)
请注意,使用Scala 2.10.0-M4无法恢复嵌套模块 - 应该可以使用M5或RC1.要使用M4测试此代码,请将模块代码替换为null.
这是一个示例:
scala> class MyClass {
object objA extends ThirdParty
object objB extends WeatherIcon
val aVal = new ThirdParty {}
val bVal = new WeatherIcon {}
def aDef = new ThirdParty {}
def bDef = new WeatherIcon {}
def anotherDef() = new ThirdParty {}
def yetAnotherDef() = new WeatherIcon {}
}
defined class MyClass
scala> invoke[ThirdParty](new MyClass)
res88: Seq[ThirdParty] = List(MyClass$$anon$5@c250cba, MyClass$$anon$3@54668d90, MyClass$$anon$1@18d8143a, null)
Run Code Online (Sandbox Code Playgroud)