Dot.Blog

C#, XAML, Xamarin, UWP/Android/iOS

Améliorer le debug sous VS avec les proxy de classes

Visual Studio est certainelement l'IDE le plus complet qu'on puisse rêver et au-delà de tout ce qu'il offre "out of the box" il est possible de lui ajouter de nombreux add-ins (gratuits ou payants) permettant de l'adapter encore plus à ses propres besoins. Ainsi vous connaissez certainement les "gros" add-ins comme Resharper dont j'ai parlé ici quelque fois ou GhostDoc qui écrit tout seul la doc des classes. Vous connaissez peut-être les add-ins de debogage permettant d'ajouter vos propres visualisateurs personnalisés pour le debug. Mais vous êtes certainement moins nombreux à connaître les proxy de classes pour le debug (Debugger Type Proxy).

A quoi cela sert-il ?

Tout d'abord cela n'a d'intérêt qu'en mode debug. Vous savez que lorsque vous placez un point d'arrêt dans votre code le debugger de VS vous permet d'inspecter le contenu des variables. C'est la base même d'un bon debugger.

La classe à deboguer 

Supposons la classe Company suivante décrivant une société stockée dans notre application. On y trouve trois propriétés, le nom de la société Company, l'ID de la société dans la base de données et la date de dernière facturation LastInvoice :

public class Customer
        {
            private string company;
            public string Company
            {
                get { return company; }
                set { company = value; }
            }
 
            private int id;
            public int ID
            {
                get { return id; }
                set { id = value; }
            }
 
            private DateTime lastInvoice;
            public DateTime LastInvoice
            {
                get { return lastInvoice; }
                set { lastInvoice = value; }
            }
        }

 

Le debug "de base" 

Supposons maintenant que nous placions un point d'arrêt dans notre application pour examiner le contenu d'une variable de type Customer, voici que nous verrons :

Le debugger affiche toutes les valeurs connues pour cette classe, les propriétés publiques comme les champs privés. Il n'y a que 3 propriétés et 3 champs dans notre classe, imaginez le fatras lorsqu'on affiche le contenu d'une instance créée depuis une classe plus riche ! Surtout qu'ici, pour tester notre application, ce dont nous avons besoin immédiatement ce sont juste deux informations claires : le nom et l'ID de la société et surtout le nombre de jours écoulés depuis la dernière facture. Retrouver l'info parmi toutes celles affichées, voire faire un calcul à la main pour celle qui nous manque, c'est transformer une session de debug qui s'annonçait plutôt bien en un véritable parcours du combattant chez les forces spéciales !

Hélas, dans la classe Customer ces informations sont soit éparpillées (nom de société et ID) soit inexistantes (ancienneté en jours de la dernière facture).

Il existe bien entendu la possibilité de créer un visualisateur personnalisé pour la classe Customer et de l'installer dans les plug-ins de Visual Studio. C'est une démarche simple mais elle réclame de créer une DLL et de la déployer sur la machine. Cette solution est parfaite en de nombreuses occasions et elle possède de gros avantages (réutilisation, facilement distribuable à plusieurs développeurs, possibilité de créer un "fiche" complète pour afficher l'information etc).

Mais il existe une autre voie, encore plus simple et plus directe : les proxy de types pour le debugger.

Un proxy de type pour simplifier

A ce stade du debug de notre application nous avons vraiment besoin du nombre de jours écoulés depuis la dernière facture et d'un moyen simple de voir immédiatement l'identification de la société. Nous ne voulons pas créer un visualisateur personnaliser, mais nous voulons tout de même une visualisation personnalisée...

Regardons le code de la classe suivante :

public class CustomerProxy
        {
            private Customer cust;
 
            public CustomerProxy(Customer cust)
            {
                this.cust = cust;
            }
 
            public string FullID
            {
                get { return cust.Company + " (" + cust.ID + ")"; }
            }
 
            public int DaysSinceLastInvoice
            {
                get { return (int) (DateTime.Now - cust.LastInvoice).TotalDays; }
            }
        }

 

la classe CustomerProxy est très (très) simple : elle possède un constructeur prenant en paramètre une instance de la classe Customer puis elle expose deux propriétés en read only : FullID qui retourne le nom de la société suivi de son ID entre parenthèses, et le nombre de jours écoulés depuis la dernière facture.

Nota: Ce code de démo ne contient aucun test... dans la réalité vous y ajouterez des tests sur null pour éviter les exceptions si l'instance passée est nulle, bien entendu.

Vous allez me dire, c'est très joli, ça fait une classe de plus dans mon code, et comment je m'en sers ? je ne vais pas modifier tout mon code pour créer des instances de cette classe cela serait délirant !

Vous avez parfaitement raison, nous n'allons pas créer d'instance de cette classe, nous n'allons pas même modifier le code de l'application en cours de debug (ce qui serait une grave erreur... modifier ce qu'on test fait perdre tout intérêt au test). Non, nous allons simplement indiquer au framework .NET qu'il utilise notre proxy lorsque VS passe en debug... Un attribut à ajouter à la classe originale Customer, c'est tout :

#if (DEBUG)
        [System.Diagnostics.DebuggerTypeProxy(typeof(CustomerProxy))]
#endif
        public class Customer
        {
            //...
        }

Vous remarquerez que pour faire plus "propre" j'ai entouré la déclaration de l'attribut dans un #if DEBUG, cela n'est absolument pas obligatoire, j'ai fait la même chose autour du code de la classe proxy. De ce fait ce code ne sera pas introduit dans l'application en mode Release. Je vous conseille cette approche malgré tout.

Et c'est fini !

Le proxy en marche

Désormais, lorsque nous sommes en debug que nous voulons voir le contenu d'une instance de la classe Customer voici ce que Visual Studio nous affiche :

 

Vous remarquez immédiatement que le contenu de l'instance de la classe Customer n'est plus affiché directement mais en place et lieu nous voyons les deux seules propriétés "artificielles" qui nous intéressent : le nom de société avec son ID, et le nombre de jours écoulés depuis la dernière facture. Fantastique non ? !

"Et si je veux voir le contenu de Customer malgré tout ?" ... Je m'attendais à cette question... Regardez sur l'image ci-dessus, oui, là, le petit "plus" dans un carré, "Raw View"... Cliquez sur le plus et vous aurez accès au même affichage de l'instance de Customer qu'en début d'article (sans le proxy) :

 

Conclusion

Si ça c'est pas de la productivité et de la customisation aux petits oignons alors je suis à court d'arguments ! :-)

Bon debug !

... Et Stay Tuned !

le projet de test : DebugProxy.zip (5,55 kb)

blog comments powered by Disqus