代码之家  ›  专栏  ›  技术社区  ›  Node.JS

scala:正确地将参数传递给methodmirror

  •  1
  • Node.JS  · 技术社区  · 7 年前

    我一直试图在scala中使用反射来创建一个简单的依赖注入容器。我面临的问题是如何正确地将参数传递给 MethodMirror . 我现在有个例外:

    java.lang.IllegalargumentException:参数类型不匹配 Java.Base/jdk.Neal.Eng.NATVEngRealToSoReRoopIMP.NeWistStase0(母语) 方法在

    容器类别:

    import scala.reflect.runtime.{universe => ru}
    import ru._
    import extensions.MapExtension._
    
    class RegisterConfig[TSource: TypeTag](container: Container){
      def as[TTrait >: TSource : TypeTag] = {
        container.typeTable += typeOf[TTrait] -> typeOf[TSource]
        container
      }
    }
    
    class InstanceConfig[TSource: TypeTag](container: Container, instance: TSource){
      def as[TTrait >: TSource : TypeTag] = {
        container.typeTable += typeOf[TTrait] -> typeOf[TSource]
        container.instances += typeOf[TTrait] -> instance
        container
      }
    }
    
    class ContainerConfig(container: Container) {
      def register[TSource: TypeTag] = new RegisterConfig(container)
    
      def instance[TSource: TypeTag](instance: TSource) = new InstanceConfig(container, instance)
    }
    
    class Container {
      var typeTable = Map[Type, Type]()
      var instances = Map[Type, Any]()
    
      def config() = new ContainerConfig(this)
    
      def resolve[TSource: TypeTag] = resolveDynamic(typeOf[TSource]).asInstanceOf[TSource]
    
      private def resolveDynamic(requestedType: Type) = {
        val resultType = typeTable.getOrElseWithCompare(requestedType, requestedType, (x, y) => x =:= y)
    
        val instance = instances.getOrElseWithCompare(resultType, createInstance(resultType), (x, y) => x =:= y)
    
        instances += resultType -> instance
    
        instance
      }
    
      private def createInstance(tpe: Type): Any = {
        val mirror: ru.Mirror = ru.runtimeMirror(getClass.getClassLoader)
        val clsSym: ru.ClassSymbol = tpe.typeSymbol.asClass
        val clsMirror: ru.ClassMirror = mirror.reflectClass(clsSym)
        val constructorSym: ru.MethodSymbol = tpe.decl(ru.termNames.CONSTRUCTOR).asMethod
        val constructorParameterTypes = constructorSym.paramLists.head.map(x => x.typeSignature)
        // Recursive step
        val params = constructorParameterTypes.map(x => resolveDynamic(x)).toArray
        // Passing `params` does not work! I get an exception here ...
        val constructorMirror: ru.MethodMirror = clsMirror.reflectConstructor(constructorSym)
        val instance = constructorMirror(params)
        instance
      }
    }
    

    单元测试:

    import org.scalatest.FlatSpec
    
    trait TestTrait
    class TestClass extends TestTrait
    class TestRecClass(x : TestTrait)
    
    class ContainerTest extends FlatSpec {
    
      "Given Trait" should "return instance (with recursion)" in {
        val container = new Container()
          .config()
          .register[TestClass]
          .as[TestTrait]
    
        val instance = container.resolve[TestRecClass]
    
        assert(instance match {
          case _: TestRecClass => true
          case null => false
        })
      }
    }
    
    0 回复  |  直到 7 年前
        1
  •  1
  •   Node.JS    7 年前

    我应该用 splat" operator 将参数数组正确传递给接受变量参数的方法

    val instance = constructorMirror(params : _*)
    
    推荐文章