Mejorar la depuración con los atributos de visualización del depurador
Actualización: noviembre 2007
Los atributos de presentación del depurador permiten al desarrollador del tipo, que especifica y mejor comprende el comportamiento en tiempo de ejecución de ese tipo, especificar el aspecto que tendrá ese tipo cuando se muestre en un depurador. Además, los atributos de presentación del depurador que proporcionan una propiedad Target pueden aplicarlos en el nivel de ensamblado los usuarios sin necesidad de conocer el código fuente. El atributo DebuggerDisplayAttribute controla la forma en que se muestra un tipo o un miembro en las ventanas de variables del depurador. El atributo DebuggerBrowsableAttribute determina si se muestra y cómo lo hace un campo o una propiedad en las ventanas de variables del depurador. El atributo DebuggerTypeProxyAttribute especifica un tipo de suplente, o un servidor proxy, para un tipo y cambia la manera en que se muestra el tipo en ventanas de depurador. Cuando se ve una variable que tiene un servidor proxy, o un tipo suplente, el servidor proxy reemplaza el tipo original en la ventana de presentación del depurador. En la ventana de las variables del depuradorse muestran sólo los miembros públicos del tipo de servidor proxy. No se muestran los miembros privados.
Utilizar DebuggerDisplayAttribute
El constructor DebuggerDisplayAttribute tiene un solo argumento: una cadena que se debe mostrar en la columna de valores de las instancias del tipo. Esta cadena puede contener llaves ({ y }). El texto incluido dentro de un par de llaves se evalúa como una expresión. Por ejemplo, el siguiente código de C# hace que se muestre "Count = 4" cuando se selecciona el signo más (+) para expandir la presentación del depurador para una instancia de MyHashtable.
[DebuggerDisplay("Count = {count}")]
class MyHashtable
{
public int count = 4;
}
No se procesan los atributos aplicados a propiedades a las que se hace referencia en la expresión. Para el compilador de C#, se permite una expresión general que sólo tiene acceso implícito a esta referencia para la instancia actual del tipo de destino. La expresión es limitada; no tiene acceso a los alias, variables locales ni punteros. En el código de C#, puede usar una expresión general entre las llaves que tenga acceso implícito al puntero this sólo para la instancia actual del tipo de destino.
Por ejemplo, si un objeto de C# tiene un ToString() reemplazado, el depurador llamará al reemplazo y mostrará su resultado en lugar del {<typeName>}. estándar. Por consiguiente, si ha reemplazado ToString(), no necesita utilizar DebuggerDisplayAttribute. Si utiliza ambos, el atributo DebuggerDisplayAttribute tiene prioridad sobre el reemplazo de ToString().
Utilizar DebuggerBrowsableAttribute
Aplique el atributo DebuggerBrowsableAttribute a un campo o propiedad para especificar cómo se debe mostrar el campo o la propiedad en la ventana del depurador. El constructor de este atributo toma uno de los valores de enumeración DebuggerBrowsableState, que especifica uno de los estados siguientes:
Never indica que el miembro no se muestra en la ventana de datos. Por ejemplo, utilizar este valor para el atributo DebuggerBrowsableAttribute en un campo quita el campo de la jerarquía; el campo no se muestra cuando se expande el tipo incluido haciendo clic en el signo más (+) de la instancia del tipo.
Collapsed indica que se muestra el miembro pero no se expande de forma predeterminada. Éste es el comportamiento predeterminado.
RootHidden indica que no se muestra el propio miembro, sino que se muestran los objetos que lo constituyen si es una matriz o colección.
Nota: |
---|
Visual Basic no admite el atributo DebuggerBrowsableAttribute en la versión 2.0 de .NET Framework. |
El ejemplo de código siguiente muestra el uso de DebuggerBrowsableAttribute para impedir que en la ventana de depuración de la clase aparezca la propiedad situada a continuación.
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public static string y = "Test String";
Utilizar DebuggerTypeProxy
Utilice el atributo DebuggerTypeProxyAttribute cuando sea necesario cambiar significativa y fundamentalmente la vista de depuración de un tipo, pero no cambie el tipo en sí. El atributo DebuggerTypeProxyAttribute se utiliza para especificar un servidor proxy de presentación para un tipo, permitiendo que los desarrolladores personalicen la vista del tipo. Este atributo, como DebuggerDisplayAttribute, se puede usar en el nivel de ensamblado, en cuyo caso la propiedad Target especifica el tipo para el que se utilizará el servidor proxy. El uso recomendado es que este atributo especifica un tipo anidado privado que aparece dentro del tipo al que se aplica el atributo. Un evaluador de expresiones que posee visores de tipo busca este atributo cuando se muestra un tipo. Si se encuentra el atributo, el evaluador de expresiones sustituye el tipo de servidor proxy de presentación por el tipo al que se aplica el atributo.
Cuando está presente el DebuggerTypeProxyAttribute, la ventana de las variables del depurador sólo muestra los miembros públicos del tipo de servidor proxy. No se muestran los miembros privados. Vistas mejoradas por atributos no cambian el comportamiento de la ventana de datos.
Para evitar pérdidas de rendimiento innecesarias, los atributos del servidor proxy de presentación no se procesan hasta que se expande el objeto, ya sea haciendo clic en el signo más (+) que aparece junto al tipo en una ventana de datos, ya a través de la aplicación del atributo DebuggerBrowsableAttribute. Por consiguiente, es recomendable no aplicar ningún atributo al tipo de presentación. Los atributos pueden y deben utilizarse en el cuerpo del tipo de presentación.
El ejemplo de código siguiente muestra el uso de DebuggerTypeProxyAttribute para especificar un tipo que se va a utilizar como un servidor proxy de presentación de depurador.
[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;
}
}
}
Ejemplo
Descripción
El ejemplo de código siguiente se puede ver en Visual Studio 2005 para observar los resultados de aplicar los atributos DebuggerDisplayAttribute, DebuggerBrowsableAttribute y DebuggerTypeProxyAttribute.
Código
Imports System
Imports System.Collections
Imports System.Diagnostics
Imports System.Reflection
Class DebugViewTest
Shared Sub Main(ByVal args() As String)
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 Const TestString As String = "This should appear in the debug window."
Public Sub New(ByVal hashtable As Hashtable)
Me.hashtable = hashtable
End Sub 'New
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(string[] args)
{
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;
}
}
}
}