12

私はこの種のクラスを得ました:

trait ThirdParty { def invoke = println("right") }

trait WeatherIcon { def invoke = println("wrong") }

class MyClass {

    object objA extends ThirdParty

    object objB extends WeatherIcon

}

ThirdPartyScala リフレクション API を使用して、含まれているオブジェクトを反復処理し、クラスのインスタンスである場合にメソッドを呼び出すにはどうすればよいですか?

4

2 に答える 2

15

socが書いたことに基づいて、私はこれを得ました:

import scala.reflect.runtime.universe._
val members = typeOf[MyClass].members.filter(_.typeSignature match {
  case tpe if tpe <:< typeOf[ThirdParty] => true
  case NullaryMethodType(tpe) if tpe <:< typeOf[ThirdParty] => true
  case MethodType(Nil, tpe) if tpe <:< typeOf[ThirdParty] => true
  case _ => false
})

パターンマッチについて説明します。avalまたは anの型はobject直接比較できますが、関数の型は少し異なります。ここでは、パラメーター リストのないメソッドとアリティ ゼロのパラメーター リストを持つメソッドを照合しています。

ここには、socの回答と比較していくつかの違いがあります。まず、members代わりにを使用しdeclarationsます。これは、継承されたメンバーと、MyClassそれ自体で宣言されたメンバーを返します。

次に、型メンバーではなく値メンバーであることを確認します。値に対してのみメソッドを呼び出すことができるため、不必要かもしれませんが、合理的な制限に見えました。更新。このisValueメソッドは 2.10.0-RC1 では使用できなくなったため、チェックを外しました。

最後に、<:<各親が等しいかどうかをチェックする代わりに使用します。

では、召喚へ。呼び出しはメンバーの種類に依存するため、上記のコードを変更します。そのため、フィルター処理と呼び出しを同時に行うことをお勧めします。それが求められていると仮定して、私も から に変更しmembersます。nonPrivateMembers更新。nonPrivateMembers2.10.0-RC1 では使用できなくなりましたfilter(!_.isPrivate)。必要に応じて使用してください。

typeOfまた、REPL のミラーでは機能しない の使用も避けます。更新。2.10.0 では RC1typeOfは問題なく動作していますが、実装の骨子はそのままにしておきます。

上記のすべては、基本的に物事の構造に関係しています: 型のメンバーが何であるか、それらがどのような種類のメンバーであるかなどです。このようなものを使いたいときは、鏡が必要です。

何か (クラス、メソッド、obj など) のシンボルまたは型がある場合はいつでも、mirrorを介してそのものに作用します。オブジェクトのインスタンスに (反射的に) 作用するには、インスタンス ミラーが必要です。メソッドを操作するには、メソッド ミラーが必要です。

それでは、要求されたことを実行する関数を作成してみましょう。

import scala.reflect.runtime.universe._
def invoke[Target : TypeTag](obj: Any): Seq[Target] = {
  val mirror = runtimeMirror(obj.getClass.getClassLoader)
  val insMirror = mirror reflect obj
  val originType = insMirror.symbol.typeSignature
  val targetType = typeTag[Target].tpe

  val members = originType.members

  val result = members collect (member => member.typeSignature match {
    case tpe if tpe <:< typeOf[ThirdParty] =>
      if (member.isModule)
        (insMirror reflectModule member.asModule).instance
      else
        (insMirror reflectField member.asTerm).get
    case NullaryMethodType(tpe) if tpe <:< typeOf[ThirdParty] =>
      (insMirror reflectMethod member.asMethod).apply()
    case MethodType(Nil, tpe) if tpe <:< typeOf[ThirdParty] =>
      (insMirror reflectMethod member.asMethod).apply()
  })

  result.map(_.asInstanceOf[Target]).toSeq
}

ネストされたモジュールは Scala 2.10.0-M4 では復元できないことに注意してください -- これは M5 または RC1 で可能になるはずです。このコードを M4 でテストするには、モジュール コードを に置き換えますnull

サンプルは次のとおりです。

scala> class MyClass {
    object objA extends ThirdParty
    object objB extends WeatherIcon
    val aVal = new ThirdParty {}
    val bVal = new WeatherIcon {}
    def aDef = new ThirdParty {}
    def bDef = new WeatherIcon {}
    def anotherDef() = new ThirdParty {}
    def yetAnotherDef() = new WeatherIcon {}
  }
defined class MyClass


scala> invoke[ThirdParty](new MyClass)
res88: Seq[ThirdParty] = List(MyClass$$anon$5@c250cba, MyClass$$anon$3@54668d90, MyClass$$anon$1@18d8143a, null)
于 2012-06-15T18:39:14.223 に答える
2

私は完全な解決策を提供することはできませんが、おそらくこれは始まりです:

import reflect.runtime.universe._

val myClassType = typeOf[MyClass]    // Get the type of McClass
val thirdPartyType = typeOf[ThirdParty] // Get the type of ThirdParty
val methodToInvoke = newTermName("invoke")

val declsOfMyClass = myClassType.declarations // Get the declarations of MyClass

val subtypesOfThirdParty = 
  declsOfMyClass.filter(_.typeSignature.parents.contains(thirdPartyType))

val methodsToInvoke =             // Now we have the methods.
  subtypesOfThirdParty.map(tps => tps.typeSignature.member(methodToInvoke))

// TODO: Invoke!

これよりもはるかに簡単な方法があると思います。

于 2012-06-15T16:07:01.613 に答える