Я хочу вызвать произвольный публичный метод произвольного материала с помощью рефлексии.То есть, скажем, я хочу написать метод extractMethod
, который будет использоваться как:
class User { def setAvatar(avatar: Avatar): Unit = …; … }
val m = extractMethod(someUser, "setAvatar")
m(someAvatar)
Из Отражения.Обзор документа из Scala docs, я вижу следующий прямой способ сделать это:
import scala.reflect.ClassTag
import scala.reflect.runtime.universe._
def extractMethod[Stuff: ClassTag: TypeTag](
stuff: Stuff,
methodName: String): MethodMirror =
{
val stuffTypeTag = typeTag[Stuff]
val mirror = stuffTypeTag.mirror
val stuffType = stuffTypeTag.tpe
val methodSymbol = stuffType
.member(TermName(methodName)).asMethod
mirror.reflect(stuff)
.reflectMethod(methodSymbol)
}
Однако, что меня беспокоит это решение, так это то, что мне нужно передать неявные ClassTag[Stuff]
и TypeTag[Stuff]
параметры (первый нужен для вызова reflect
, второй - для получения stuffType
).Что может быть довольно громоздким, особенно если extractMethod
вызывается из обобщенных элементов, которые вызываются из обобщенных элементов и так далее.Я бы принял это как необходимость для некоторых языков, в которых сильно отсутствует информация о типах среды выполнения, но Scala основана на JRE, что позволяет делать следующее:
def extractMethod[Stuff](
stuff: Stuff,
methodName: String,
parameterTypes: Array[Class[_]]): (Object*) => Object =
{
val unboundMethod = stuff.getClass()
.getMethod(methodName, parameterTypes: _*)
arguments => unboundMethod(stuff, arguments: _*)
}
Я понимаю, что отражение в Scala позволяет получить больше информацииэто основное отражение Java.Тем не менее, здесь мне просто нужно вызвать метод.Есть ли способ как-то уменьшить требования (например, ClassTag
, TypeTag
) версии extractMethod
на основе отражения Scala (без возврата к отражению на чистой Java), предполагая, что производительность для меня не имеет значения