with what usar type from done create como reflection scala name-mangling

usar - what can be done with reflection in c#



Scala: ¿cómo puedo instanciar dinámicamente un objeto e invocar un método utilizando la reflexión? (5)

En caso de que necesite invocar un método de un objeto Scala 2.10 (no clase) y tenga los nombres del método y el objeto como String s, puede hacerlo así:

package com.example.mytest import scala.reflect.runtime.universe class MyTest object MyTest { def target(i: Int) = println(i) def invoker(objectName: String, methodName: String, arg: Any) = { val runtimeMirror = universe.runtimeMirror(getClass.getClassLoader) val moduleSymbol = runtimeMirror.moduleSymbol( Class.forName(objectName)) val targetMethod = moduleSymbol.typeSignature .members .filter(x => x.isMethod && x.name.toString == methodName) .head .asMethod runtimeMirror.reflect(runtimeMirror.reflectModule(moduleSymbol).instance) .reflectMethod(targetMethod)(arg) } def main(args: Array[String]): Unit = { invoker("com.example.mytest.MyTest$", "target", 5) } }

Esto imprime 5 a la salida estándar. Más detalles en Scala Documentation .

En Scala, ¿cuál es la mejor manera de crear instancias dinámicas de un objeto e invocar un método utilizando la reflexión?

Me gustaría hacer un equivalente de Scala del siguiente código de Java:

Class class = Class.forName("Foo"); Object foo = class.newInstance(); Method method = class.getMethod("hello", null); method.invoke(foo, null);

En el código anterior, tanto el nombre de clase como el nombre del método se pasan dinámicamente. El mecanismo de Java anterior probablemente podría usarse para Foo y hello() , pero los tipos de Scala no coinciden uno a uno con los de Java. Por ejemplo, una clase puede declararse implícitamente para un objeto singleton. También el método de Scala permite que todo tipo de símbolos sea su nombre. Ambos se resuelven por cambio de nombre. Ver Interop entre Java y Scala .

Otro problema parece ser la coincidencia de parámetros al resolver sobrecargas y autoboxing, descrito en Reflection from Scala - Heaven and Hell .


Existe una manera más fácil de invocar el método de forma reflexiva sin recurrir a la invocación de métodos de reflexión de Java: use Structural Typing.

Simplemente eche la referencia del objeto a un Tipo Estructural que tenga la firma del método necesaria y luego invoque el método: no se requiere reflexión (por supuesto, Scala está haciendo una reflexión debajo pero no necesitamos hacerlo).

class Foo { def hello(name: String): String = "Hello there, %s".format(name) } object FooMain { def main(args: Array[String]) { val foo = Class.forName("Foo").newInstance.asInstanceOf[{ def hello(name: String): String }] println(foo.hello("Walter")) // prints "Hello there, Walter" } }


La parte de instanciación podría usar el Manifest : ver esta respuesta SO

característica experimental en Scala llamada manifiestos que son una forma de evitar una restricción de Java con respecto al borrado de tipos

class Test[T](implicit m : Manifest[T]) { val testVal = m.erasure.newInstance().asInstanceOf[T] }

Con esta versión todavía escribes

class Foo val t = new Test[Foo]

Sin embargo, si no hay ningún constructor no-arg disponible, se obtiene una excepción de tiempo de ejecución en lugar de un error de tipo estático

scala> new Test[Set[String]] java.lang.InstantiationException: scala.collection.immutable.Set at java.lang.Class.newInstance0(Class.java:340)

Entonces, la verdadera solución de tipo seguro sería usar una fábrica.

Nota: como se indica en este hilo , Manifest está aquí para quedarse, pero es por ahora "el único uso es dar acceso a la eliminación del tipo como una instancia de clase".

Lo único que manifiesta ahora es la eliminación del tipo estático de un parámetro en el sitio de llamada (a diferencia de getClass que le da el borrado del tipo dinámico ).

A continuación, puede obtener un método a través de la reflexión:

classOf[ClassName].getMethod("main", classOf[Array[String]])

e invocarlo

scala> class A { | def foo_=(foo: Boolean) = "bar" | } defined class A scala>val a = new A a: A = A@1f854bd scala>a.getClass.getMethod(decode("foo_="), classOf[Boolean]).invoke(a, java.lang.Boolean.TRUE) res15: java.lang.Object = bar


Las respuestas de VonC y son bastante buenas, así que simplemente me complementaré con una característica experimental de Scala 2.8. De hecho, ni siquiera me molestaré en disfrazarlo, solo copiaré el scaladoc.

object Invocation extends AnyRef

Una sintaxis más conveniente para la invocación reflexiva. Ejemplo de uso:

class Obj { private def foo(x: Int, y: String): Long = x + y.length }

Puedes llamarlo reflexivamente de dos maneras:

import scala.reflect.Invocation._ (new Obj) o ''foo(5, "abc") // the ''o'' method returns Any val x: Long = (new Obj) oo ''foo(5, "abc") // the ''oo'' method casts to expected type.

Si llama al método oo y no le proporciona suficiente ayuda al tipo inferencer, lo más probable es que infiera Nothing, lo que dará como resultado una ClassCastException.

Autor Paul Phillips


Trabajando a partir de la respuesta de @ nedim, aquí hay una base para una respuesta completa, la principal diferencia se encuentra a continuación, instanciamos clases ingenuas. Este código no maneja el caso de múltiples constructores, y de ninguna manera es una respuesta completa.

import scala.reflect.runtime.universe case class Case(foo: Int) { println("Case Case Instantiated") } class Class { println("Class Instantiated") } object Inst { def apply(className: String, arg: Any) = { val runtimeMirror: universe.Mirror = universe.runtimeMirror(getClass.getClassLoader) val classSymbol: universe.ClassSymbol = runtimeMirror.classSymbol(Class.forName(className)) val classMirror: universe.ClassMirror = runtimeMirror.reflectClass(classSymbol) if (classSymbol.companion.toString() == "<none>") // TODO: use nicer method "hiding" in the api? { println(s"Info: $className has no companion object") val constructors = classSymbol.typeSignature.members.filter(_.isConstructor).toList if (constructors.length > 1) { println(s"Info: $className has several constructors") } else { val constructorMirror = classMirror.reflectConstructor(constructors.head.asMethod) // we can reuse it constructorMirror() } } else { val companionSymbol = classSymbol.companion println(s"Info: $className has companion object $companionSymbol") // TBD } } } object app extends App { val c = Inst("Class", "") val cc = Inst("Case", "") }

Aquí hay un build.sbt que lo compilaría:

lazy val reflection = (project in file(".")) .settings( scalaVersion := "2.11.7", libraryDependencies ++= Seq( "org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided", "org.scala-lang" % "scala-library" % scalaVersion.value % "provided" ) )