2010-06-14 12 views
30

powiedzieć, mam następujący:Jak wywołać metodę Scala Object za pomocą odbicia?

trait SomeTrait { 
    def someMethod: String; 
} 

object SomeObject extends SomeTrait { 
    def someMethod = "something"; 
} 

chciałbym nazwać „metodę someMethod” przy użyciu odbicia jak mam nazwę obiektu jako ciąg znaków. Coś jak:

val objectName = "SomeObject" 
val someTrait:SomeTrait = ???.asInstanceOf[SomeTrait] 
someTrait.someMethod 

lub coś podobnego.

Dzięki

Odpowiedz

13

Dla klas, można to zrobić bardzo łatwo za pomocą standardowej metody classOf java refleksji. Dla obiektów Scala, to jest trochę więcej pracy, ale wciąż można zrobić:


trait SomeTrait { def someMethod: String} 
object SomeObject extends SomeTrait { def someMethod = "something"} 

class SomeClass extends SomeTrait { def someMethod = "something"} 

object Main { 
def main(args:Array[String]) = { 
    val someClassTrait:SomeTrait = Class.forName("SomeClass").newInstance().asInstanceOf[SomeTrait] 
    println("calling someClassTrait: " + someClassTrait.someMethod) 
    val objectName = "SomeObject$" 
    val cons = Class.forName(objectName).getDeclaredConstructors(); 
    cons(0).setAccessible(true); 
    val someObjectTrait:SomeTrait = cons(0).newInstance().asInstanceOf[SomeTrait] 
    println("calling someObjectTrait: " + someObjectTrait.someMethod) 
    } 
} 

//prints: 
calling someClassTrait: something 
calling someObjectTrait: something 
+2

myślę to robi przerwij oczekiwanie klientów obiektu towarzyszącego (singleton), jeśli utworzysz nowe jego instancje. –

+0

Arjan - dzięki. Właśnie tego szukałem. Thomas - To prawda. Ale zawsze możesz zawinąć kod w fabrykę obiektów i samemu dostarczyć zachowania singleton. – sanjib

19
def companion[T](name : String)(implicit man: Manifest[T]) : T = 
    Class.forName(name + "$").getField("MODULE$").get(man.erasure).asInstanceOf[T] 

val result = companion[SomeTrait]("SomeObject").someMethod 
+0

To jeszcze lepiej. Dzięki, Thomas. – sanjib

+2

Czy potrzebujesz manifestu? Znalazłem, że 'Class.forName (name +" $ "). GetField (" MODULE $ "). Get (null)' jest wystarczające. Jest to dozwolone w przypadku pól statycznych. –

+1

Jak tłumaczy się w 2.10 z odbiciem? – bhericher

12

Od Scala 2.10, możemy użyć odbicie module:

import scala.reflect.runtime.universe 

val runtimeMirror = universe.runtimeMirror(getClass.getClassLoader) 
val module = runtimeMirror.staticModule("SomeObject") 
val obj = runtimeMirror.reflectModule(module) 
val someTrait:SomeTrait = obj.instance.asInstanceOf[SomeTrait] 
someTrait.someMethod 
Powiązane problemy