Implementazione di ExpandoObject in Scala
-
27-10-2019 - |
Domanda
Sto cercando di implementare la classe ExpandoObject
di C # in Scala.Ecco come dovrebbe funzionare:
val e = new ExpandoObject
e.name := "Rahul" // This inserts a new field `name` in the object.
println(e.name) // Accessing its value.
Ecco cosa ho provato finora:
implicit def enrichAny[A](underlying: A) = new EnrichedAny(underlying)
class EnrichedAny[A](underlying: A) {
// ...
def dyn = new Dyn(underlying.asInstanceOf[AnyRef])
}
class Dyn(x: AnyRef) extends Dynamic {
def applyDynamic(message: String)(args: Any*) = {
new Dyn(x.getClass.getMethod(message,
args.map(_.asInstanceOf[AnyRef].getClass) : _*).
invoke(x, args.map(_.asInstanceOf[AnyRef]) : _*))
}
def typed[A] = x.asInstanceOf[A]
override def toString = "Dynamic(" + x + ")"
}
class ExpandoObject extends Dynamic {
private val fields = mutable.Map.empty[String, Dyn]
def applyDynamic(message: String)(args: Any*): Dynamic = {
fields get message match {
case Some(v) => v
case None => new Assigner(fields, message).dyn
}
}
}
class Assigner(fields: mutable.Map[String, Dyn], message: String) {
def :=(value: Any): Unit = {
fields += (message -> value.dyn)
}
}
Quando provo a compilare questo codice, ottengo un StackOverflowError
.Per favore aiutami a ottenere questo lavoro.:) Grazie.
Soluzione
Funziona dopo aver giocato un po '.La soluzione però non è sicura per i tipi (cosa che in questo caso non ha importanza, poiché lo scopo di questa piccola utility è aggirare il sistema dei tipi. :-)
trait ExpandoObject extends Dynamic with mutable.Map[String, Any] {
lazy val fields = mutable.Map.empty[String, Any]
def -=(k: String): this.type = { fields -= k; this }
def +=(f: (String, Any)): this.type = { fields += f; this }
def iterator = fields.iterator
def get(k: String): Option[Any] = fields get k
def applyDynamic(message: String)(args: Any*): Any = {
this.getOrElse(message, new Assigner(this, message))
}
}
implicit def anyToassigner(a: Any): Assigner = a match {
case x: Assigner => x
case _ => sys.error("Not an assigner.")
}
class Assigner(ob: ExpandoObject, message: String) {
def :=(value: Any): Unit = ob += (message -> value)
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow