2013-04-18 5 views
25

Wie kann ich die Feldwerte aus einer Fallklasse in scala mit dem neuen Reflexionsmodell in scala 2.10 extrahieren? Zum Beispiel ist der unter Verwendung nicht die FeldmethodenScala 2.10 reflection, wie extrahiere ich die Feldwerte aus einer Fallklasse

def getMethods[T:TypeTag](t:T) = typeOf[T].members.collect { 
    case m:MethodSymbol => m 
    } 

ich sie in

for {field <- fields} { 
    currentMirror.reflect(caseClass).reflectField(field).get 
    } 

Antwort

39

MethodSymbol zu pumpen plane herausziehen hat eine isCaseAccessor Methode, die Ihnen genau dies zu tun erlaubt:

def getMethods[T: TypeTag] = typeOf[T].members.collect { 
    case m: MethodSymbol if m.isCaseAccessor => m 
}.toList 

Jetzt können Sie die folgende schreiben:

scala> case class Person(name: String, age: Int) 
defined class Person 

scala> getMethods[Person] 
res1: List[reflect.runtime.universe.MethodSymbol] = List(value age, value name) 

Und Sie erhalten nur die Methode Symbole, die Sie wollen.

+0

Ah merke ich jetzt, dass mein Ansatz falsch war. Irgendeine Idee, wie man die caseAccessors von einer unbekannten Fallklasse bekommt? IE eine, die derzeit in als val SomeCaseClass gespeichert ist: Beliebig –

+0

Warten, nicht bekommen currentMirror.reflect (someCaseClass) .symbol.asType.typeSignature.members –

+0

Kann dies mit Multi-Thread-Umgebung unter scala 2.10 arbeiten? – jilen

10

Wenn Sie schicker werden möchten, können Sie sie in Ordnung bringen, indem Sie das Konstruktorsymbol überprüfen. Dieser Code funktioniert auch dann, wenn für den betreffenden Fallklassentyp mehrere Konstruktoren definiert sind.

import scala.collection.immutable.ListMap 
    import scala.reflect.runtime.universe._ 

    /** 
    * Returns a map from formal parameter names to types, containing one 
    * mapping for each constructor argument. The resulting map (a ListMap) 
    * preserves the order of the primary constructor's parameter list. 
    */ 
    def caseClassParamsOf[T: TypeTag]: ListMap[String, Type] = { 
    val tpe = typeOf[T] 
    val constructorSymbol = tpe.decl(termNames.CONSTRUCTOR) 
    val defaultConstructor = 
     if (constructorSymbol.isMethod) constructorSymbol.asMethod 
     else { 
     val ctors = constructorSymbol.asTerm.alternatives 
     ctors.map(_.asMethod).find(_.isPrimaryConstructor).get 
     } 

    ListMap[String, Type]() ++ defaultConstructor.paramLists.reduceLeft(_ ++ _).map { 
     sym => sym.name.toString -> tpe.member(sym.name).asMethod.returnType 
    } 
    } 
+0

Ich finde Fälle, in denen dies mit "scala.ScalaReflectionException: ist kein Begriff" im Ausdruck "constructorSymbol.asTerm.alternatives". Der Dokumentationskommentar für "Deklaration" bezieht sich auf "ÜberladenesSymbol", aber eine solche Entität scheint nicht zu existieren. –

+0

Es stellt sich heraus, dass dies passierte, weil ich es mit "this.type" von einem Merkmal aus nannte, das als Supertyp der betreffenden Fallklasse verwendet wurde. –

+0

Auch "Fallklasse P (i: Int) (j: Int)". –