2016-06-10 54 views
0

我正在處理一些使用自定義枚舉的代碼來確保完整性檢查,並且它需要使用反射來獲取可能值的列表。類似下面的代碼已經在代碼庫中(所有不相關的東西都被刪除和/或重命名)我已經將它們放在一起成爲獨立的可運行格式。在自定義枚舉中使用反射來獲取可能的值

import scala.reflect.runtime.universe.TypeTag 

object ReflectionUtil { 

    def modules[A : TypeTag](parent: Any) = { 
    import scala.reflect.runtime.{currentMirror, universe} 
    val members = currentMirror.classSymbol(parent.getClass).toType.members 
     .filter{ symbol => 
     println(s"$symbol: ${symbol.typeSignature} <:< ${universe.typeOf[A]} is ${symbol.typeSignature <:< universe.typeOf[A]}") 
     symbol.typeSignature <:< universe.typeOf[A] 
     } 
    } 
} 

trait Enumeration { 
    type Value <: V 

    protected[this] trait V 

    lazy val values = ReflectionUtil.modules[V](this) 
} 

object Switch extends Enumeration { 
    sealed trait Value extends V 
    case object On extends Value 
    case object Off extends Value 
} 

object Main { 
    def main(args: Array[String]) = println(Switch.values) 
} 

這裏的問題是對於出現的一切,你可以在輸出中看到返回false行symbol.typeSignature <:< universe.typeOf[A]

object Off: Switch.Off.type <:< Enumeration.this.V is false 
object On: Switch.On.type <:< Enumeration.this.V is false 
constructor Switch:()Switch.type <:< Enumeration.this.V is false 
value values: => scala.Unit <:< Enumeration.this.V is false 
trait V: scala.AnyRef { 

} <:< Enumeration.this.V is false 
method $init$:()scala.Unit <:< Enumeration.this.V is false 
method $asInstanceOf: [T0]()T0 <:< Enumeration.this.V is false 
method $isInstanceOf: [T0]()Boolean <:< Enumeration.this.V is false 
method synchronized: [T0](x$1: T0)T0 <:< Enumeration.this.V is false 
method ##:()Int <:< Enumeration.this.V is false 
method !=: (x$1: Any)Boolean <:< Enumeration.this.V is false 
method ==: (x$1: Any)Boolean <:< Enumeration.this.V is false 
method ne: (x$1: AnyRef)Boolean <:< Enumeration.this.V is false 
method eq: (x$1: AnyRef)Boolean <:< Enumeration.this.V is false 
method notifyAll:()Unit <:< Enumeration.this.V is false 
method notify:()Unit <:< Enumeration.this.V is false 
method clone:()java.lang.Object <:< Enumeration.this.V is false 
method getClass:()java.lang.Class[_] <:< Enumeration.this.V is false 
method hashCode:()Int <:< Enumeration.this.V is false 
method toString:()java.lang.String <:< Enumeration.this.V is false 
method equals: (x$1: Any)Boolean <:< Enumeration.this.V is false 
method wait:()Unit <:< Enumeration.this.V is false 
method wait: (x$1: Long)Unit <:< Enumeration.this.V is false 
method wait: (x$1: Long, x$2: Int)Unit <:< Enumeration.this.V is false 
method finalize:()Unit <:< Enumeration.this.V is false 
method asInstanceOf: [T0]=> T0 <:< Enumeration.this.V is false 
method isInstanceOf: [T0]=> Boolean <:< Enumeration.this.V is false 
() 

注輸出的前兩行。 即使對於看起來應該符合的類型(我實際上感興趣的枚舉類型),爲什麼它總是會返回false,我該如何解決這個問題?

要重申:我所期待從lazy val values得到的是相關枚舉對象來說OnOffSwitch,這需要自動化,因此它可以與許多其他枚舉類型喜歡的工作。

回答

0

爲了後代的緣故,我會回答我自己的問題。

這是按預期工作代碼:

import scala.reflect.runtime.universe._ 
import scala.reflect.runtime.currentMirror 

object ReflectionUtil { 

    def modules[A : TypeTag](parent: Any): Iterable[A] = { 
    val baseType = typeOf[A] 
    for { 
     symbol <- currentMirror.classSymbol(parent.getClass).toType.members 
     if symbol.isModule && symbol.info.widen <:< baseType 
    } yield currentMirror.reflectModule(symbol.asModule).instance.asInstanceOf[A] 
    } 
} 

trait EnumeratedValue 

trait Enumeration { 
    type Value <: EnumeratedValue 

    lazy val values = ReflectionUtil.modules[EnumeratedValue](this) 
} 

object Switch extends Enumeration { 
    sealed trait Value extends EnumeratedValue 
    case object On extends Value 
    case object Off extends Value 
} 

object Main { 
    def main(args: Array[String]) = println(Switch.values) 
} 

事實證明,因爲特徵被嵌入到生成的類的字節碼,內部特徵是不能跨使用外部特徵的所有類相同。因此,它正在檢查與函數定義中實際傳遞的不同特徵是否一致。通過將相關特徵拉出Enumeration特徵之外,該功能現在可以正確解析特徵,因此它按預期工作。