如何使用scala反射API来获取所有包含的类

时间:2012-06-15 15:19:26

标签: scala reflection

我有这样的课程:

trait ThirdParty { def invoke = println("right") }

trait WeatherIcon { def invoke = println("wrong") }

class MyClass {

    object objA extends ThirdParty

    object objB extends WeatherIcon

}

如果它是ThirdParty类的实例,我如何使用Scala反射API迭代包含的对象并调用方法?

2 个答案:

答案 0 :(得分: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
})

让我解释模式匹配。可以直接比较valobject的类型,但函数的类型略有不同。在这里,我将匹配没有参数列表的方法,以及具有零参数列表的方法。

与soc的答案相比,这里存在一些差异。首先,我使用members代替declarations。这将返回继承的成员以及在MyClass本身上声明的成员。

其次,我检查它是值成员,而不是类型成员。您只能在值上调用方法,因此它看起来是合理的限制,尽管可能没有必要。 UPD。 {1}}方法在2.10.0-RC1中不再可用,因此我删除了支票。

最后,我使用isValue而不是检查每个父级是否相等。

现在,来调用。我将更改上面的代码,因为调用取决于您拥有的成员类型,因此我们最好同时进行过滤和调用。我也将从<:<更改为members,假设这是想要的。 UPD。 2.10.0-RC1中不再提供nonPrivateMembers,必要时请使用nonPrivateMembers

而且我也会避免使用filter(!_.isPrivate),这不适用于REPL上的镜像。 UPD。在2.10.0-RC1 typeOf工作正常,但我会保持实现的骨架不变。

以上所有内容基本上都与事物的结构有关:一种类型的成员是什么,他们是什么样的成员,等等。如果你想使用这个东西,你需要镜子。

每当你有一个符号或类型的东西 - 类,方法,obj等 - 你通过镜像对这个东西采取行动。要(反射地)对象的实例进行操作,您需要一个实例镜像。要对方法执行操作,您需要一个方法镜像,依此类推。

因此,让我们尝试构建一个功能来完成所要求的工作:

typeOf

请注意,使用Scala 2.10.0-M4无法恢复嵌套模块 - 应该可以使用M5或RC1。要使用M4测试此代码,请将模块代码替换为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 }

以下是一个示例:

null

答案 1 :(得分:2)

我无法提供完整的解决方案,但也许这是一个开始:

import reflect.runtime.universe._

val myClassType = typeOf[MyClass]    // Get the type of McClass
val thirdPartyType = typeOf[ThirdParty] // Get the type of ThirdParty
val methodToInvoke = newTermName("invoke")

val declsOfMyClass = myClassType.declarations // Get the declarations of MyClass

val subtypesOfThirdParty = 
  declsOfMyClass.filter(_.typeSignature.parents.contains(thirdPartyType))

val methodsToInvoke =             // Now we have the methods.
  subtypesOfThirdParty.map(tps => tps.typeSignature.member(methodToInvoke))

// TODO: Invoke!

我想有比这更直截了当的方式。

相关问题