Ответ 1
Основываясь на том, что написал 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
})
Позвольте мне объяснить совпадение шаблонов. Тип a val
или object
можно сравнивать напрямую, но функции имеют несколько иной тип. Здесь я сопоставляю методы, не содержащие списков параметров, и методы с нулевым параметром.
Здесь есть несколько отличий от социального ответа. Во-первых, я использую 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 и т.д., вы воздействуете на эту вещь через зеркало. Чтобы действовать (отражательно) на экземпляр объекта, вам нужно зеркало экземпляра. Чтобы действовать по методу, вам нужно зеркало метода и т.д.
Итак, попробуйте создать functon, чтобы выполнить запрошенное:
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
}
Обратите внимание, что вложенные модули не могут быть восстановлены с помощью 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([email protected], [email protected], [email protected], null)