是否可以使用反射来查找声明为Scala枚举子类型的字段的实际类型?
我想自动将字符串转换/强制转换为Scala枚举值,但事先不知道声明来自哪个枚举子类(subobject?) 因此,鉴于:是否可以使用反射来查找声明为Scala枚举子类型的字段的实际类型?,scala,reflection,enumeration,Scala,Reflection,Enumeration,我想自动将字符串转换/强制转换为Scala枚举值,但事先不知道声明来自哪个枚举子类(subobject?) 因此,鉴于: object MyEnumeration extends Enumeration { type MyEnumeration = Value val FirstValue, SecondValue = Value } 及 我将如何实现以下内容 val myThing = new MyThing() setByReflection(myThing, "whichOne"
object MyEnumeration extends Enumeration {
type MyEnumeration = Value
val FirstValue, SecondValue = Value
}
及
我将如何实现以下内容
val myThing = new MyThing()
setByReflection(myThing, "whichOne", "SecondValue")
我发现,当我获得MyThing.whichOne类(通过java.lang.Field)时,返回的是“scala.Enumeration$Value”,它不够具体,无法枚举所有可能值的名称。特定类型在运行时丢失,但您可以在编译时通过隐式捕获它。您可以在枚举中提供如下所示的隐式
object MyEnumeration extends Enumeration {
type MyEnumeration = Value
val FirstValue, SecondValue = Value
implicit def convertMyEnumeration( value: String ) =
MyEnumeration.withName( value )
}
class MyThing {
import MyEnumeration._
var whichOne: MyEnumeration = FirstValue
}
val myThing = new MyThing()
myThing.whichOne = "SecondValue"
class MySuperThing {
def setWhichOne( value: String }
}
class MyThing extends MySuperThing {
import MyEnumeration._
var whichOne: MyEnumeration = FirstValue
def setWhichOne( value: String ) = MyEnumeration.withName( value )
}
val myThing: MySuperThing = new MyThing()
myThing.setWhichOne( "SecondValue" )
如果类型系统无法解析枚举以在用法中应用正确的隐式,您也可以执行以下操作。您可以默认使用多态性,并提供如下设置程序
object MyEnumeration extends Enumeration {
type MyEnumeration = Value
val FirstValue, SecondValue = Value
implicit def convertMyEnumeration( value: String ) =
MyEnumeration.withName( value )
}
class MyThing {
import MyEnumeration._
var whichOne: MyEnumeration = FirstValue
}
val myThing = new MyThing()
myThing.whichOne = "SecondValue"
class MySuperThing {
def setWhichOne( value: String }
}
class MyThing extends MySuperThing {
import MyEnumeration._
var whichOne: MyEnumeration = FirstValue
def setWhichOne( value: String ) = MyEnumeration.withName( value )
}
val myThing: MySuperThing = new MyThing()
myThing.setWhichOne( "SecondValue" )
查看my,它将告诉您有关枚举字段类型的所有信息,只要它们在包范围内声明(没有内部类枚举、函数范围枚举)
您需要为它提供枚举字段的scala类型(可以通过scala的反射接口找到)(请参见下文,了解如何从类[\uz]获取此字段)
如何获取enumObjectType
val typ = typeOf[EC]
// OR
val typ = getTypeForClass(classOf[EC]) // or from your package scanner
val enumGetters = classAccessors( typ ).filter(EnumReflector.isEnumeration(_))
// Let's looks at the 1st enum field
val reflector = EnumReflector(enumGetters.head.returnType)
val fieldName = enumGetters.head.name.toString
。。。现在您需要使用Java反射来为这个类找到相同的方法。Scala有实例反射,但要求您在运行时对实例进行反射(这很慢)。最好获得Java反射调用方法的句柄:
val enumGetter = toJavaClass(typ).getMethods.filter(_.getName==fieldName).head
从你的
val obj = new MyThing()
现在,您可以获取对象的枚举字段,并通过反射器解释其名称或id:
val enumObj = enumGetter.invoke(obj)
val name = reflector.toName(enumObj)
val enumObj2 reflector.fromName(name)
assertTrue( enumObj2 eq enumObj )
支持功能:
import scala.reflect.runtime.universe._
val mirror = runtimeMirror(this.getClass.getClassLoader)
def toJavaClass(tpe:Type) = mirror.runtimeClass(tpe.typeSymbol.asClass)
def getTypeForClass(clazz: Class[_]): Type = mirror.classSymbol(clazz).toType
def classGetters(typ:Type) = typ.members.collect{case m:MethodSymbol=> m}.filter(_.isGetter)
def classAccessors(typ:Type) = typ.members.collect{case m:MethodSymbol=> m}.filter(_.isAccessor)
项目中有一个单元测试来演示它。也许2.10版本中会有新的反射API?谢谢你的建议,Neil,但对于我的问题来说,找到使用反射的类型是至关重要的。我已经更新了问题的标题,使之更清楚。