2010-04-17 15 views
10

Betrachten Sie den folgenden Code zuzugreifen:Wie ein Feldwert über Reflexion (Scala 2.8)

class Foo(var name: String = "bar") 

Jetzt versuche ich, den Wert und die richtige Art die es durch Reflexion zu erhalten:

val foo = new Foo 
val field = foo.getClass.getDeclaredField("name") 
field.setAccessible(true) 
//This is where it doesn't work 
val value = field.get(????) 

Ich habe Dinge wie field.get (foo) ausprobiert, aber das gibt nur ein java.lang.Object, aber keinen String zurück. Im Grunde brauche ich den richtigen Typ, weil ich eine Methode darauf aufrufen will (zB toCharArray).

Was ist der vorgeschlagene Weg, das zu tun?

Antwort

0

Es sieht so aus, dass nicht möglich ist, zu tun, was ich mit wollen versuchen, alle möglichen Typen von Hand e. G.

o match { 
    case I if o.isInstanceOf[Int] => val i = I.asInstanceOf[Int] 
    case F if o.isInstanceOf[Float] => val f = I.asInstanceOf[Float] 
    case S if o.isInstanceOf[String] => val s = I.asInstanceOf[String] 
    case OF if o.getGenericType.toString == "scala.Option<java.lang.Float>" => val of = OF.asInstanceOf[Option[Float]] 
    . 
    . 
    . 

Nun, lassen Sie uns es hoffen, dass eine Sprache, in der Zukunft sein, wenn so etwas wie das funktioniert ...

3

getDeclaredField ist eine Methode von java.lang.Class.

Sie müssen foo.getDeclaredField("name") zu foo.getClass.getDeclaredField("name") (oder classOf[Foo].getDeclaredField("name")) ändern, um das Feld zu erhalten.

Sie können den Typ mit getType Methode in Klasse Field erhalten, aber es wird Ihnen nicht helfen, weil es Class[_] zurückgibt. Wenn Sie wissen, dass der Typ ein String ist, können Sie den zurückgegebenen Wert immer mit field.get(foo).asInstanceOf[String]

+0

Ich reparierte die fehlende getClass, das war nur ein Versehen. Ich frage mich, wie man die Besetzung tun, ohne vorher zu wissen, was es ist. Wenn ich alles über die Klasse wusste, die ich behandeln muss, würde ich Reflexion nicht brauchen ... Danke für die Vorschläge! – soc

+0

Sie können das Objekt mit einem Muster wie "Wert Übereinstimmung {Fall s: String =>/* Machen Sie etwas mit einer Zeichenfolge */Fall _ =>/* machen Sie etwas anderes * /}' Muster übereinstimmen. Ich weiß nicht, ob ich verstehe, was du machen willst. – gerferra

1

AFAIK, Reflexion immer mit Object arbeiten, und Sie müssen die Ergebnisse selbst umwandeln.

+0

Ja, ich hatte die Frage missverstanden, jetzt habe ich meine Antwort geändert. – gerferra

5

Wie andere bereits erwähnt haben, geben die Reflektionsmethoden Object zurück, so dass Sie umwandeln müssen. Sie können besser die Methode verwenden, die der Scala-Compiler für den Feldzugriff erstellt, anstatt die Sichtbarkeit des privaten Felds ändern zu müssen. (Ich bin nicht einmal sicher, ob der Name privaten Bereich gewährleistet ist die gleiche wie die der Accessormethoden sein.)

val foo = new Foo 
val method = foo.getClass.getDeclaredMethod("name") 
val value = method.get(foo).asInstanceOf[String] 
+0

funktioniert gut mit ** foo.getClass.getDeclaredField ("name") ** weil foo.getClass.getDeclaredMethod kein Mitglied namens * get * hat – Kruser

0

Dies ist, wie eine Liste der Feldnamen und seinen Wert einer Fallklasse bekommen kann:
Zuerst, mit Reflektion, erhalten Felder Informationen wie folgt -

val TUPLE2_OF_FIELDNAME_TO_GETTERS = typeOf[<CLASS>].members 
.filter(!_.isMethod) 
.map(x => (x.name.toString, classOf[<CLASS>].getDeclaredMethod(x.name.toString.trim))) 

Wie man es benutzt?

getFieldNameAndValue(obj: <CLASS>): Seq[(String, String)] { 
    var output = Seq[(String, String)]() 
for(fieldToGetter <- TUPLE2_OF_FIELDNAME_TO_GETTERS) { 
     val fieldNameAsString = fieldToGetter._1 
     val getter = fieldToGetter._2 
     val fieldValue = getter.invoke(obj).toString 
     output += (fieldName, fieldValue) 
    } 
}