Pour faciliter l'introspection du temps de débogage dans les classes, je voudrais effectuer une méthode de totrage générique dans la classe de base pour les objets en question. Comme il n'est pas du code critique de la performance, j'aimerais utiliser la réflexion pour imprimer des paires de noms / valeur de champ ("x = 1, y = 2", etc.). P>
Y a-t-il un moyen facile de faire cela? J'ai essayé plusieurs solutions potentielles et avons couru contre les problèmes d'accès à la sécurité, etc. p>
Pour être clair, la méthode Tostring () dans la classe de base doit réfléchir à la réflexion sur les vals publics dans toutes les classes qui héritent de celle-ci, ainsi que de tous les traits mélangés. P>
4 Réponses :
Exemple:
override def toString() = { getClass().getDeclaredFields().map { field:Field => field.setAccessible(true) field.getName() + ": " + field.getType() + " = " + field.get(this).toString() }.deepMkString("\n") }
J'utilise déjà quelque chose de similaire à cela, mais je reçois beaucoup d'exceptions d'accès, même pour les choses qui sont des vals publics. Je suis confus à ce sujet, comme je m'attendais à ce que je m'attendais à ce que j'avais du code comme celui-ci: la classe FOO {VAL BAR = 3} que si j'ai appelé, à partir d'une autre classe, FOO.GETDECLaredfield ("bar"), l'objet de terrain résultant aurait le modificateur "public". J'utilise java.lang.reflect.MODIFIC.MODIFICE pour décoder les champs de modificateur et ne fonctionne pas. Ceci est en 2.7.7, je ne suis donc pas sûr que cela diffère de 2,8 à cet égard.
J'ai trouvé que val obj = champ.get (ceci); Val Str = obj.ASInstance de [string] code> ne fonctionne pas. Bizarre
Pour ceux qui utilisent Scala 2.10, remplacez Deepmkstring i> avec mkstring i>
Scala ne génère aucun domaine public. Ils vont tous être privés. Les méthodes accessoires sont ce qui sera public, réfléchir à ceux-ci. Compte tenu d'une classe comme: Le bytecode généré ressemble à: p>
Je crois qu'une fois il y a longtemps, j'avais l'habitude de le savoir. Merci!
import util._ // For Scala 2.8.x NameTransformer import scala.tools.nsc.util._ // For Scala 2.7.x NameTransformer /** * Repeatedly run `f` until it returns None, and assemble results in a Stream. */ def unfold[A](a: A, f: A => Option[A]): Stream[A] = { Stream.cons(a, f(a).map(unfold(_, f)).getOrElse(Stream.empty)) } def get[T](f: java.lang.reflect.Field, a: AnyRef): T = { f.setAccessible(true) f.get(a).asInstanceOf[T] } /** * @return None if t is null, Some(t) otherwise. */ def optNull[T <: AnyRef](t: T): Option[T] = if (t eq null) None else Some(t) /** * @return a Stream starting with the class c and continuing with its superclasses. */ def classAndSuperClasses(c: Class[_]): Stream[Class[_]] = unfold[Class[_]](c, (c) => optNull(c.getSuperclass)) def showReflect(a: AnyRef): String = { val fields = classAndSuperClasses(a.getClass).flatMap(_.getDeclaredFields).filter(!_.isSynthetic) fields.map((f) => NameTransformer.decode(f.getName) + "=" + get(f, a)).mkString(",") } // TEST trait T { val t1 = "t1" } class Base(val foo: String, val ?? : Int) { } class Derived(val d: Int) extends Base("foo", 1) with T assert(showReflect(new Derived(1)) == "t1=t1,d=1,??=1,foo=foo")
J'aurais dû mentionner que je suis coincé avec 2.7.7 pour l'instant. Je n'étais pas sûr de certaines des nouvelles constructions 2.8 que vous avez utilisées dans votre code et que vous avez terminé avec une exception Null Pointer. Cela ressemble à un moyen assez propre de le faire, alors la réponse va à vous!
Savez-vous que les classes de cas Scala obtiennent ces méthodes générées par compilateur: P>
Ils obtiennent également des objets de compagnon pour des constructeurs "nouveaux" et une correspondance de modèle " P>
Le TOSTRING () code généré est à peu près comme celui que vous décrivez. P>
Oui, les classes de cas sont magiques. Malheureusement, je ne les utilise pas ici, pour diverses raisons. J'utilise toutes les fonctionnalités que vous avez énumérées dans d'autres endroits. Je serai sûr que mon trait de tostring peut gérer des classes de cas à l'avenir. En outre, vous vous voyez sur IRC hier soir, petit monde.
Ne devrait-il pas être un trait?
TRAIT TOSTRING [A] CODE>?
Cela pourrait être le moyen le plus propre de le faire, je n'ai pas pensé à la manière dont cela a une incidence sur mon héritière de l'objet. J'ai des problèmes d'accès à la propriété que je ne peux pas expliquer actuellement.
Les réponses ici, en utilisant spécifiquement Apache ReflextringtostringBuilder, ne sont pas une mauvaise idée: Stackoverflow.com/Questtions/603013/...