Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
El DebuggerDisplayAttribute controla cómo se muestra un objeto, una propiedad o un campo en las ventanas de variables del depurador. Este atributo se puede aplicar a tipos (clases, estructuras, enumeraciones, delegados), pero normalmente solo se aplica a clases y estructuras. Si se aplica a un tipo base, el atributo también se aplica a una subclase.
El atributo DebuggerDisplay tiene un único argumento, que es una cadena que se va a mostrar en la columna de valor para las instancias del tipo. Esta cadena puede contener llaves ({ y }). El texto dentro de un par de llaves se evalúa como un campo, propiedad o método.
Si una clase tiene un método de ToString() invalidado, el depurador usa el método invalidado en lugar del valor predeterminado {<typeName>}. En este caso, no tiene que usar DebuggerDisplay. Si usa ambos, el atributo DebuggerDisplay tiene prioridad sobre el método ToString() invalidado. El atributo DebuggerDisplay también tiene prioridad sobre el método ToString() invalidado en una subclase.
Si el depurador evalúa esta llamada implícita ToString() depende de una opción depuración en Herramientas (o Depurar) >Opciones.
Important
Si selecciona la opción Mostrar estructura sin procesar de objetos en las ventanas de variables , se omite el DebuggerDisplay atributo . Esta configuración se encuentra en el panel Herramientas>Opciones de la sección Todos los ajustes>Depuración>General.
Important
Si selecciona la opción Mostrar estructura sin procesar de objetos en las ventanas de variables , se omite el DebuggerDisplay atributo . Esta configuración se encuentra en el cuadro de diálogoOpciones de > de la sección Depuración>general.
Note
En el caso del código nativo, este atributo solo se admite en código de C++/CLI.
En la tabla siguiente se muestran algunos posibles usos del atributo DebuggerDisplay y salidas de ejemplo.
| Attribute | Salida que aparece en la columna Valor |
|---|---|
[DebuggerDisplay("x = {x} y = {y}")]Se usa en un tipo con campos x y y. |
x = 5 y = 18 |
[DebuggerDisplay("String value is {getString()}")]sintaxis de parámetros puede variar entre idiomas. Por lo tanto, úselo con cuidado. |
String value is [5, 6, 6] |
DebuggerDisplay también puede aceptar parámetros con nombre.
| Parameters | Purpose |
|---|---|
Name, Type |
Estos parámetros afectan las columnas Nombre y Tipo de las ventanas de variables. (Se pueden establecer en cadenas con la misma sintaxis que el constructor). Usar estos parámetros o usarlos incorrectamente puede provocar una salida confusa. |
Target, TargetTypeName |
Especifica el tipo de destino cuando se usa el atributo en el nivel de ensamblado. |
El archivo autoexp.cs usa el atributo DebuggerDisplay en el nivel de ensamblado. El archivo autoexp.cs determina las expansiones predeterminadas que Visual Studio usa para los objetos .NET. Puede examinar el archivo autoexp.cs para ver ejemplos de cómo usar el atributo DebuggerDisplay, o bien puede modificar y compilar el archivo autoexp.cs para cambiar las expansiones predeterminadas. Asegúrese de realizar una copia de seguridad del archivo autoexp.cs antes de modificarlo.
Para compilar autoexp.cs, abra un Símbolo del sistema para desarrolladores para VS2015 y ejecute los siguientes comandos
cd <directory containing autoexp.cs>
csc /t:library autoexp.cs
Los cambios en autoexp.dll se recogerán en la siguiente sesión de depuración.
Uso de expresiones en DebuggerDisplay
Aunque puedes usar una expresión general entre corchetes en un atributo de DebuggerDisplay, no se recomienda esta práctica.
Una expresión general de DebuggerDisplay tiene acceso implícito al puntero this solo para la instancia actual del tipo de destino. La expresión no tiene acceso a alias, variables locales o punteros. Si la expresión hace referencia a propiedades, no se procesan los atributos de esas propiedades. Por ejemplo, el código de C# [DebuggerDisplay("Object {count - 2}")] mostraría Object 6 si el campo count era 8.
El uso de expresiones en DebuggerDisplay puede provocar los siguientes problemas:
Evaluar expresiones es la operación más costosa en el depurador y la expresión se evalúa cada vez que se muestra. Esto puede causar problemas de rendimiento al recorrer el código. Por ejemplo, una expresión compleja que se usa para mostrar los valores de una colección o lista puede ser muy lenta cuando el número de elementos es grande.
Las expresiones se evalúan mediante el evaluador de expresiones del lenguaje del marco de pila actual y no por el evaluador del lenguaje en el que se escribió la expresión. Esto puede provocar resultados imprevisibles cuando los idiomas son diferentes.
Evaluar una expresión puede cambiar el estado de la aplicación. Por ejemplo, una expresión que establece el valor de una propiedad muta el valor de propiedad en el código en ejecución.
Una manera de reducir los posibles problemas de evaluación de expresiones es crear una propiedad privada que realice la operación y devuelva una cadena. El atributo DebuggerDisplay puede mostrar el valor de esa propiedad privada. En el ejemplo siguiente se implementa este patrón:
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed class MyClass
{
public int count { get; set; }
public bool flag { get; set; }
private string DebuggerDisplay
{
get
{
return string.Format("Object {0}", count - 2);
}
}
}
El sufijo ",nq" indica al evaluador de expresiones que quite las comillas al mostrar el valor final (nq = sin comillas). Para obtener más información sobre los formateadores, vea Especificadores de formato en C#.
Example
En el ejemplo de código siguiente se muestra cómo usar DebuggerDisplay, junto con DebuggerBrowsable y DebuggerTypeProxy. Cuando se ve en una ventana de variables del depurador, como la ventana Inspección, genera una expansión similar a la siguiente:
| Name | Value | Type |
|---|---|---|
| Key | "three" | objeto {string} |
| Value | 3 | objeto {int} |
[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;
}
public object Key
{
get { return key; }
set
{
object tempValue = dictionary[key];
dictionary.Remove(key);
key = value;
dictionary.Add(key, tempValue);
}
}
public object Value
{
get { return this.value; }
set
{
this.value = value;
dictionary[key] = this.value;
}
}
}
[DebuggerDisplay("{DebuggerDisplay,nq}")]
[DebuggerTypeProxy(typeof(HashtableDebugView))]
class MyHashtable
{
public Hashtable hashtable;
public MyHashtable()
{
hashtable = new Hashtable();
}
private string DebuggerDisplay { get { return "Count = " + hashtable.Count; } }
private class HashtableDebugView
{
private MyHashtable myhashtable;
public HashtableDebugView(MyHashtable myhashtable)
{
this.myhashtable = myhashtable;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePairs[] Keys
{
get
{
KeyValuePairs[] keys = new KeyValuePairs[myhashtable.hashtable.Count];
int i = 0;
foreach (object key in myhashtable.hashtable.Keys)
{
keys[i] = new KeyValuePairs(myhashtable.hashtable, key, myhashtable.hashtable[key]);
i++;
}
return keys;
}
}
}
}