Amélioration du débogage avec les attributs d'affichage de débogueur
Les attributs d'affichage de débogueur permettent au développeur du type, qui spécifie et appréhende le mieux le comportement d'exécution de ce type, de spécifier également ce à quoi le type ressemblera une fois affiché dans un débogueur. De plus, les attributs d'affichage de débogueur qui fournissent une propriété Target peuvent être appliqués au niveau de l'assembly par des utilisateurs sans qu'il leur soit nécessaire de connaître le code source. L'attribut DebuggerDisplayAttribute contrôle la façon dont un type ou un membre s'affiche dans les fenêtres de variables du débogueur. L'attribut DebuggerBrowsableAttribute contrôle si une classe ou un champ s'affiche dans les fenêtres de variables du débogueur et comment ils s'affichent. L'attribut DebuggerTypeProxyAttribute spécifie un type de substitution, ou un proxy, d'un type et modifie le mode d'affichage de ce type dans les fenêtres de débogage. Lorsque vous visualisez une variable possédant un proxy, ou un type de substitution, ce dernier remplace le type d'origine dans la fenêtre d'affichage du débogage. La fenêtre de variables du débogueur n'affiche que les membres publics du type du proxy. Les membres privés ne sont pas affichés.
Utilisation de DebuggerDisplayAttribute
Le constructeur DebuggerDisplayAttribute possède un argument unique : une chaîne à afficher dans la colonne valeur pour les instances du type. Cette chaîne peut contenir des accolades ({ et }). Le texte entre accolades est évalué comme une expression. Par exemple, le code C# suivant entraîne l'affichage de "Count = 4" lorsque le signe plus (+) est sélectionné pour développer l'affichage de débogueur pour une instance de MyHashtable.
[DebuggerDisplay("Count = {count}")]
class MyHashtable
{
public int count = 4;
}
Les attributs appliqués aux propriétés référencées dans l'expression ne sont pas traités. Pour le compilateur C#, une expression générale est autorisée si elle ne possède qu'un accès implicite à cette référence pour l'instance actuelle du type cible. L'expression est limitée ; il n'existe aucun accès aux alias, aux variables locales ou aux pointeurs. En code C#, vous pouvez utiliser une expression générale entre accolades qui dispose d'un accès implicite au pointeur this uniquement pour l'instance actuelle du type cible.
Si, par exemple, un objet C# a un ToString() substitué, le débogueur appellera la substitution et affichera son résultat au lieu du {<typeName>}. standard. Si vous avez substitué ToString(), vous ne devez donc pas utiliser DebuggerDisplayAttribute. Si vous utilisez les deux, l'attribut DebuggerDisplayAttribute prend la priorité sur la substitution de ToString().
Utilisation de DebuggerBrowsableAttribute
Appliquez l'attribut DebuggerBrowsableAttribute à un champ ou une propriété pour spécifier la façon dont le champ ou la propriété doit être affiché dans la fenêtre du débogueur. Le constructeur pour cet attribut accepte l'une des valeurs d'énumération DebuggerBrowsableState qui spécifient l'un des états suivants :
Never indique que le membre n'est pas affiché dans la fenêtre de données. Par exemple, l'utilisation de cette valeur pour DebuggerBrowsableAttribute sur un champ supprime le champ de la hiérarchie ; le champ n'est pas affiché lorsque vous développez le type englobant en cliquant sur le signe plus (+) pour l'instance de type.
Collapsed indique que le membre est affiché mais n'est pas développé par défaut. Il s'agit du comportement par défaut.
RootHidden indique que le membre lui-même n'est pas affiché, mais ses objets constituants sont affichés s'il s'agit d'un tableau ou d'une collection.
Remarque |
---|
DebuggerBrowsableAttribute n'est pas pris en charge dans la version 2.0 du .NET Framework. |
L'exemple de code suivant illustre l'utilisation du DebuggerBrowsableAttribute pour empêcher la propriété qui le suit d'apparaître dans la fenêtre de débogage pour la classe.
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public static string y = "Test String";
Utilisation de DebuggerTypeProxy
Utilisez l'attribut DebuggerTypeProxyAttribute lorsque vous avez besoin de modifier radicalement l'affichage de débogage d'un type, sans toutefois modifier le type lui-même. L'attribut DebuggerTypeProxyAttribute est utilisé pour spécifier un proxy d'affichage pour un type, ce qui permet à un développeur d'adapter l'affichage pour le type. Cet attribut, à l'instar de DebuggerDisplayAttribute, peut être utilisé également au niveau de l'assembly, auquel cas la propriété Target spécifie le type pour lequel le proxy sera utilisé. Il est généralement recommandé que cet attribut spécifie un type imbriqué privé qui se produit dans le type auquel l'attribut est appliqué. Évaluateur d'expression qui prend en charge des contrôles de visionneuses de type pour cet attribut lors de l'affichage d'un type. Si l'attribut est trouvé, l'évaluateur d'expression substitue le type du proxy d'affichage au type auquel l'attribut est appliqué.
Lorsque DebuggerTypeProxyAttribute est présent, la fenêtre des variables du débogueur affiche uniquement les membres publics du type de proxy. Les membres privés ne sont pas affichés. Le comportement de la fenêtre de données n'est pas modifié par les affichages améliorés par les attributs.
Pour éviter une dégradation inutile des performances, les attributs du proxy d'affichage ne sont pas traités tant que l'objet n'est pas développé, soit par un clic de l'utilisateur sur le signe plus (+) en regard du type dans une fenêtre de données, soit via l'application de l'attribut DebuggerBrowsableAttribute. Par conséquent, il est recommandé de n'appliquer aucun attribut au type d'affichage. Les attributs peuvent et doivent être appliqués dans le corps du type d'affichage.
L'exemple de code suivant montre comment utiliser DebuggerTypeProxyAttribute pour spécifier un type à utiliser en tant que proxy de l'affichage du débogueur.
[DebuggerTypeProxy(typeof(HashtableDebugView))]
class MyHashtable : Hashtable
{
private const string TestString =
"This should not appear in the debug window.";
internal class HashtableDebugView
{
private Hashtable hashtable;
public const string TestStringProxy =
"This should appear in the debug window.";
// The constructor for the type proxy class must have a
// constructor that takes the target type as a parameter.
public HashtableDebugView(Hashtable hashtable)
{
this.hashtable = hashtable;
}
}
}
Exemple
Description
L'exemple de code suivant peut être affiché dans Visual Studio 2005 pour consulter les résultats de l'application des attributs DebuggerDisplayAttribute, DebuggerBrowsableAttribute et DebuggerTypeProxyAttribute.
Code
Imports System
Imports System.Collections
Imports System.Diagnostics
Imports System.Reflection
Class DebugViewTest
' The following constant will appear in the debug window for DebugViewTest.
Const TabString As String = " "
' The following DebuggerBrowsableAttribute prevents the property following it
' from appearing in the debug window for the class.
<DebuggerBrowsable(DebuggerBrowsableState.Never)> _
Public Shared y As String = "Test String"
Shared Sub Main()
Dim myHashTable As New MyHashtable()
myHashTable.Add("one", 1)
myHashTable.Add("two", 2)
Console.WriteLine(myHashTable.ToString())
Console.WriteLine("In Main.")
End Sub 'Main
End Class 'DebugViewTest
<DebuggerDisplay("{value}", Name := "{key}")> _
Friend Class KeyValuePairs
Private dictionary As IDictionary
Private key As Object
Private value As Object
Public Sub New(ByVal dictionary As IDictionary, ByVal key As Object, ByVal value As Object)
Me.value = value
Me.key = key
Me.dictionary = dictionary
End Sub 'New
End Class 'KeyValuePairs
<DebuggerDisplay("Count = {Count}"), DebuggerTypeProxy(GetType(MyHashtable.HashtableDebugView))> _
Class MyHashtable
Inherits Hashtable
Private Const TestString As String = "This should not appear in the debug window."
Friend Class HashtableDebugView
Private hashtable As Hashtable
Public Shared TestString As String = "This should appear in the debug window."
Public Sub New(ByVal hashtable As Hashtable)
Me.hashtable = hashtable
End Sub 'New
<DebuggerBrowsable(DebuggerBrowsableState.RootHidden)> _
ReadOnly Property Keys as KeyValuePairs()
Get
Dim nkeys(hashtable.Count) as KeyValuePairs
Dim i as Integer = 0
For Each key As Object In hashtable.Keys
nkeys(i) = New KeyValuePairs(hashtable, key, hashtable(key))
i = i + 1
Next
Return nkeys
End Get
End Property
End Class 'HashtableDebugView
End Class 'MyHashtable
using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
class DebugViewTest
{
// The following constant will appear in the debug window for DebugViewTest.
const string TabString = " ";
// The following DebuggerBrowsableAttribute prevents the property following it
// from appearing in the debug window for the class.
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public static string y = "Test String";
static void Main()
{
MyHashtable myHashTable = new MyHashtable();
myHashTable.Add("one", 1);
myHashTable.Add("two", 2);
Console.WriteLine(myHashTable.ToString());
Console.WriteLine("In Main.");
}
}
[DebuggerDisplay("{value}", Name = "{key}")]
internal class KeyValuePairs
{
private IDictionary dictionary;
private object key;
private object value;
public KeyValuePairs(IDictionary dictionary, object key, object value)
{
this.value = value;
this.key = key;
this.dictionary = dictionary;
}
}
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(HashtableDebugView))]
class MyHashtable : Hashtable
{
private const string TestString = "This should not appear in the debug window.";
internal class HashtableDebugView
{
private Hashtable hashtable;
public const string TestString = "This should appear in the debug window.";
public HashtableDebugView(Hashtable hashtable)
{
this.hashtable = hashtable;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePairs[] Keys
{
get
{
KeyValuePairs[] keys = new KeyValuePairs[hashtable.Count];
int i = 0;
foreach(object key in hashtable.Keys)
{
keys[i] = new KeyValuePairs(hashtable, key, hashtable[key]);
i++;
}
return keys;
}
}
}
}
using namespace System;
using namespace System::Collections;
using namespace System::Diagnostics;
using namespace System::Reflection;
ref class HashtableDebugView;
[DebuggerDisplay("{value}", Name = "{key}")]
ref class KeyValuePairs
{
private:
IDictionary^ dictionary;
Object^ key;
Object^ value;
public:
KeyValuePairs(IDictionary^ dictionary, Object^ key, Object^ value)
{
this->value = value;
this->key = key;
this->dictionary = dictionary;
}
};
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(HashtableDebugView::typeid)]
ref class MyHashtable : Hashtable
{
private:
static const String^ TestString = "This should not appear in the debug window.";
internal:
ref class HashtableDebugView
{
private:
Hashtable^ hashtable;
public:
static const String^ TestString = "This should appear in the debug window.";
HashtableDebugView(Hashtable^ hashtable)
{
this->hashtable = hashtable;
}
[DebuggerBrowsable(DebuggerBrowsableState::RootHidden)]
property array<KeyValuePairs^>^ Keys
{
array<KeyValuePairs^>^ get()
{
array<KeyValuePairs^>^ keys = gcnew array<KeyValuePairs^>(hashtable->Count);
IEnumerator^ ie = hashtable->Keys->GetEnumerator();
int i = 0;
Object^ key;
while (ie->MoveNext())
{
key = ie->Current;
keys[i] = gcnew KeyValuePairs(hashtable, key, hashtable[key]);
i++;
}
return keys;
}
}
};
};
public ref class DebugViewTest
{
private:
// The following constant will appear in the debug window for DebugViewTest.
static const String^ TabString = " ";
public:
// The following DebuggerBrowsableAttribute prevents the property following it
// from appearing in the debug window for the class.
[DebuggerBrowsable(DebuggerBrowsableState::Never)]
static String^ y = "Test String";
static void Main()
{
MyHashtable^ myHashTable = gcnew MyHashtable();
myHashTable->Add("one", 1);
myHashTable->Add("two", 2);
Console::WriteLine(myHashTable->ToString());
Console::WriteLine("In Main.");
}
};
int main()
{
DebugViewTest::Main();
}