这是很合乎逻辑的。您正在显式返回Any
. 一种解决方法是始终拥有 Dynamic 的实例:
import language.dynamics
import scala.collection.mutable.HashMap
import scala.reflect.ClassTag
trait DynamicBase extends Dynamic {
def as[T:ClassTag]: T
def selectDynamic[T](name: String): DynamicBase
def updateDynamic(name:String)(value: Any)
}
class ReflectionDynamic( val self: Any ) extends DynamicBase with Proxy {
def as[T:ClassTag]: T = { implicitly[ClassTag[T]].runtimeClass.asInstanceOf[Class[T]].cast( self ) }
// TODO: cache method lookup for faster access + handle NoSuchMethodError
def selectDynamic[T](name: String): DynamicBase = {
val ref = self.asInstanceOf[AnyRef]
val clazz = ref.getClass
clazz.getMethod(name).invoke( ref ) match {
case dyn: DynamicBase => dyn
case res => new ReflectionDynamic( res )
}
}
def updateDynamic( name: String )( value: Any ) = {
val ref = self.asInstanceOf[AnyRef]
val clazz = ref.getClass
// FIXME: check parameter type, and handle overloads
clazz.getMethods.find(_.getName == name+"_=").foreach{ meth =>
meth.invoke( ref, value.asInstanceOf[AnyRef] )
}
}
}
object Main extends DynamicBase {
def as[T:ClassTag]: T = { implicitly[ClassTag[T]].runtimeClass.asInstanceOf[Class[T]].cast( this ) }
private val map = new HashMap[String, DynamicBase]
def selectDynamic[T](name: String): DynamicBase = { map(name) }
def updateDynamic(name:String)(value: Any) = {
val dyn = value match {
case dyn: DynamicBase => dyn
case _ => new ReflectionDynamic( value )
}
map(name) = dyn
}
}
用法:
scala> class Figure {
| val bla: String = "BLA"
| }
defined class Figure
scala> val fig = new Figure() // has a method number
fig: Figure = Figure@6d1fa2
scala> Main.figname = fig
Main.figname: DynamicBase = Figure@6d1fa2
scala> Main.figname.bla
res40: DynamicBase = BLA
所有实例都包装在一个动态实例中。as
我们可以使用执行动态转换的方法来恢复实际类型。
scala> val myString: String = Main.figname.bla.as[String]
myString: String = BLA