Sobre la base de lo que escribió soc, tengo esto:
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
})
Voy a explicar la coincidencia de patrón. El tipo de val
o object
se puede comparar directamente, pero las funciones tienen un tipo ligeramente diferente. Aquí estoy haciendo coincidir los métodos sin listas de parámetros y los métodos con una lista de parámetros de aria cero.
Aquí hay algunas diferencias en comparación con la respuesta de soc. Primero, uso members
en lugar de declarations
. Eso devuelve los miembros heredados, así como los que se declaran en MyClass
sí mismo.
En segundo lugar, compruebo que es un miembro de valor, a diferencia de un miembro de tipo. Solo puede invocar métodos sobre valores, por lo que parecía una restricción razonable, aunque tal vez innecesaria. upd. El método isValue
ya no está disponible en 2.10.0-RC1, por lo que eliminé el cheque.
Finalmente, uso <:<
en lugar de verificar la igualdad de cada padre.
Ahora, a la invocación. Voy a cambiar el código anterior, ya que la invocación depende del tipo de miembro que tenga, por lo que será mejor que hagamos el filtrado y la invocación al mismo tiempo. También cambiaré de members
a nonPrivateMembers
, suponiendo que eso es lo que quiero. upd. nonPrivateMembers
ya no está disponible en 2.10.0-RC1, use filter(!_.isPrivate)
si es necesario.
Y también evitaré el uso de typeOf
, que no funcionará con espejos en el REPL. upd. En 2.10.0-RC1 typeOf
está funcionando bien, pero mantendré el esqueleto de la implementación sin cambios.
Todo lo anterior se refiere básicamente a la estructura de las cosas: qué son los miembros de un tipo, qué tipo de miembros son, y así sucesivamente. Cuando quiera use esto, necesita espejos.
Siempre que tenga un símbolo o un tipo para algo - una clase, método, obj, etc. - actúa sobre esa cosa a través de un espejo . Para actuar (reflexivamente) en una instancia de un objeto, necesita un espejo de instancia. Para actuar en un método, necesita un espejo de método, y así sucesivamente.
Así que vamos a tratar de construir una functon a hacer lo que se solicitó:
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
}
Tenga en cuenta que anida módulos no se pueden recuperar con Scala 2.10.0-M4 - que debería ser posible con M5 o RC1. Para probar este código con M4, reemplace el código del módulo con null
.
He aquí una muestra:
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([email protected], [email protected], [email protected], null)
Mucho mejor que mi ejemplo! ¡Gracias! – soc
Creo que typeSignature devuelve NullaryMethodTypes, que no son subtipos de ThirdParty? ¿Podrías imprimir '_.typeSignature.kind'? –
La parte de invocación se puede hacer con la API de réplicas. Más información aquí: http://stackoverflow.com/questions/11020746/get-companion-object-instance-with-new-scala-reflection-api/11031443#11031443. En resumen, tendrá que hacer 'runtimeMirror (getClass.getClassLoader) .reflect (). ReflectMethod () ()' –