2010-06-14 27 views
30

nói, tôi đã điều sau đây:Làm thế nào để gọi một phương thức đối tượng Scala bằng cách sử dụng sự phản chiếu?

trait SomeTrait { 
    def someMethod: String; 
} 

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

tôi muốn gọi là "someMethod" sử dụng phản chiếu như tôi có tên đối tượng như là một String. Một cái gì đó như:

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

hoặc tương tự.

Cảm ơn

Trả lời

13

Đối với các lớp học, điều này có thể được thực hiện khá dễ dàng bằng cách sử dụng lớp phản chiếu java chuẩn. Đối với đối tượng Scala, nó là công việc nhiều hơn một chút, nhưng nó vẫn có thể được thực hiện:


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

Tôi nghĩ rằng nó phá vỡ sự mong đợi của khách hàng của đối tượng đồng hành (singleton) nếu bạn tạo ra các phiên bản mới của nó. –

+0

Arjan - cảm ơn. Đó chính xác là những gì tôi đang tìm kiếm. Thomas - Đúng vậy. Nhưng bạn luôn có thể quấn mã trong một nhà máy đối tượng và tự cung cấp hành vi 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

Điều này thậm chí còn tốt hơn. Cảm ơn Thomas. – sanjib

+2

Bạn có cần tệp kê khai không? Tôi thấy rằng 'Class.forName (tên +" $ "). GetField (" MODULE $ "). Get (null)' là đủ. Điều này được cho phép đối với các trường tĩnh. –

+1

Làm thế nào để dịch trong 2,10 với sự phản ánh? – bhericher

12

Kể từ scala 2.10, chúng ta có thể sử dụng sự phản xạ của 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 
Các vấn đề liên quan