2011-10-20 12 views
7

Sto cercando di implementare la classe C#'s ExpandoObject in Scala. Ecco come dovrebbe funzionare:Implementazione di ExpandoObject in Scala

val e = new ExpandoObject 
e.name := "Rahul" // This inserts a new field `name` in the object. 
println(e.name) // Accessing its value. 

Ecco quello che 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.

risposta

4

Ha funzionato dopo aver giocato un po '. La soluzione non è però tipicamente idonea (che in questo caso non ha importanza, dal momento che questa piccola utilità è quella di aggirare il sistema di 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) 
} 
+0

Puoi dare un esempio di utilizzo? –

+0

Nel mio caso particolare, devo elaborare alcuni dati strutturati in fogli Excel, di cui non so nulla in fase di compilazione. Trattare tali dati come record a livello di lingua rende l'elaborazione più semplice. – missingfaktor

+0

È possibile fare riferimento all'articolo collegato sopra per ulteriori esempi. – missingfaktor

Problemi correlati