Поделиться через


Использование атрибута DebuggerDisplay

Атрибут DebuggerDisplay (System.Diagnostics.DebuggerDisplayAttribute) управляет тем, как класс или поле отображается в окнах переменных отладчика. Данный атрибут может применяться к:

  • Классы

  • структурам;

  • Делегаты

  • перечислениям;

  • полям;

  • Свойства

  • Сборки

Атрибут DebuggerDisplay имеет один аргумент, определяющий строку, которая должна отображаться в столбце "Значение" для экземпляров типа. Эта строка может содержать фигурные скобки ({ и }). Текст, заключенный в фигурные скобки, будет вычисляться как поле, свойство или метод.

Если в объекте C# имеется переопределенный метод ToString(), отладчик будет вызывать переопределенный метод и отображать возвращаемый им результат, а не имя типа ({<typeName>}). Таким образом, если был переопределен метод ToString(), атрибут DebuggerDisplay использовать не требуется. Если используется и то и другое, то атрибут DebuggerDisplay будет иметь более высокий приоритет по отношению к переопределению ToString().

Будет ли отладчик выполнять неявный вызов метода ToString() , зависит от заданных параметров пользователя в диалоговом окне Параметры (категория Отладка, страница Общие). В Visual Basic неявный вызов метода ToString() не производится.

Важно!

Если в диалоговом окне Сервис, Параметры установлен флажок Показывать базовую структуру объектов в окнах переменных, атрибут DebuggerDisplay игнорируется.

В следующей таблице показано несколько примеров возможного использования атрибута DebuggerDisplay для вывода строк удобочитаемого вида.

Атрибут

Строка, выводимая в столбце Значение

[DebuggerDisplay("x = {x} y = {y}")]

Применение для типа с полями x и y.

x = 5 y = 18

[DebuggerDisplay("String value is {getString()}")]Синтаксис параметра может различаться в зависимости от языка. Будьте внимательны при его использовании.

String value is [5, 6, 6]

Атрибут DebuggerDisplay также может принимать именованные параметры.

Параметры

Назначение

Name, Type

Эти параметры влияют на столбцы Имя и Тип окон переменных. (Для них также может быть задан вывод строк с использованием того же синтаксиса, что и для конструктора.) Злоупотребление этими параметрами или их неправильное использование может, однако, привести к выводу неудобочитаемых или недостоверных данных.

Target, TargetTypeName

Указывает конечный тип, когда атрибут используется на уровне сборки.

Примечание

Файл autoexp.cs использует атрибут DebuggerDisplay на уровне сборки.Файл autoexp.cs определяет расширения по умолчанию, которые Visual Studio использует для переменных C#.В файле autoexp.cs можно посмотреть примеры использования атрибута DebuggerDisplay. При необходимости в файл autoexp.cs можно внести изменения и откомпилировать его, чтобы изменить расширения по умолчанию.Прежде чем изменять файл autoexp.cs, следует обязательно сделать его резервную копию.Необходимо сослаться на Microsoft.VisualStudio.DebuggerVisualizers.dll в 12.0\Common7\IDE\PublicAssemblies \Program Files\Microsoft Visual Studio.Файл autoexp.cs можно найти в папке My Documents/Visual Studio 2012/Visualizers.

Использование выражений в атрибуте DebuggerDisplay

Хотя в атрибуте DebuggerDisplay допускается использовать общее выражение внутри фигурных скобок, делать это не рекомендуется.

Общее выражение внутри атрибута DebuggerDisplay имеет неявный доступ к указателю this только для текущего экземпляра конечного типа. Выражение не имеет доступа к псевдонимам, локальным переменным или указателям. Если выражение ссылается на свойства, то атрибуты для этих свойств не обрабатываются. Например, код C# [DebuggerDisplay("Object {count - 2}" отобразил бы Object 6, если бы поле count имело значение 8.

Использование выражений в атрибуте DebuggerDisplay может привести к следующим проблемам:

  • Вычисление выражений является наиболее ресурсоемкой операцией в отладчике, причем выражение вычисляется при каждом его отображении. Это может вызвать проблемы производительности при пошаговом выполнении кода. Например, сложное выражение, используемое для отображения значений в коллекции или в списке, при большом количестве элементов может вычисляться очень медленно.

  • Выражения вычисляются с помощью вычислителя выражений языка текущего кадра стека, а не языка, на котором было написано выражение. Это может привести к непредсказуемым результатам, если языки различаются.

  • Вычисление выражения может изменить состояние приложения. Например, выражение, которое задает значение свойства, изменяет значение свойства в выполняемом коде.

Одним из способов сократить возможные проблемы вычисления выражения является создание закрытого свойства, которое выполняет операцию и возвращает строку. Атрибут DebuggerDisplay сможет отобразить значение этого закрытого свойства. Ниже показан пример реализации этого способа.

[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); }    }}

Пример

Следующий пример демонстрирует способ использования атрибута DebuggerDisplay совместно с атрибутами DebuggerBrowseable и DebuggerTypeProxy. При работе данного кода в окна переменных отладчика, например в окно Контрольные значения, выводится расширенная информация, а именно:

Имя

Значение

Тип

Ключ

"три"

object {string}

Значение

3

object {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;
            }
        }
    }
}

См. также

Ссылки

Использование атрибута DebuggerTypeProxy

Основные понятия

Отображение пользовательских типов данных

Повышение эффективности отладки с помощью атрибутов просмотра отладчика