Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
DebuggerDisplayAttribute управляет отображением объекта, свойства или поля в окнах переменных отладчика. Этот атрибут может применяться к типам (классам, структурым, перечислениям, делегатам), но обычно применяется только к классам и структурым. При применении к базовому типу атрибут также применяется к подклассу.
Атрибут DebuggerDisplay имеет один аргумент, который является строкой, отображаемой в столбце значений для экземпляров типа. Эта строка может содержать фигурные скобки ({ и }). Текст в паре фигурных скобок оценивается как поле, свойство или метод.
Если класс имеет переопределенный метод ToString(), отладчик использует переопределенный метод вместо {<typeName>}по умолчанию. В этом случае вам не нужно использовать DebuggerDisplay. Если вы используете оба, атрибут DebuggerDisplay имеет приоритет над переопределённым методом ToString(). Атрибут DebuggerDisplay также имеет приоритет над переопределенным методом ToString() в подклассе.
Независимо от того, оценивает ли отладчик этот неявный ToString() вызов, зависит от параметра отладки в разделе "Средства" (или ">").
Important
Если выбрать Показать необработанную структуру объектов в окнах переменных, DebuggerDisplay атрибут игнорируется. Этот параметр находится в разделе Инструменты>Параметры в области Все параметры>Отладка>Общие.
Important
Если выбрать параметр Показать необработанную структуру объектов в окнах переменных, DebuggerDisplay атрибут игнорируется. Этот параметр расположен в диалоговом окне"Параметры>" в разделе"Общие сведения > отладке".
Note
Для машинного кода этот атрибут поддерживается только в коде C++/CLI.
В следующей таблице показаны некоторые возможные способы использования атрибута DebuggerDisplay и примеров выходных данных.
| Attribute | Результаты, отображаемые в столбце "Значение" |
|---|---|
[DebuggerDisplay("x = {x} y = {y}")]Используется для типа с полями x и y. |
x = 5 y = 18 |
[DebuggerDisplay("String value is {getString()}")]синтаксис параметров может отличаться между языками. Поэтому используйте его с осторожностью. |
String value is [5, 6, 6] |
DebuggerDisplay также может принимать именованные параметры.
| Parameters | Purpose |
|---|---|
Name, Type |
Эти параметры влияют на столбцы Имя и Тип окон переменных. (Их можно задать для строк, используя тот же синтаксис, что и конструктор.) Чрезмерное использование этих параметров или их неправильное использование может привести к путанице выходных данных. |
Target, TargetTypeName |
Указывает целевой тип, когда атрибут используется на уровне сборки. |
Файл autoexp.cs использует атрибут DebuggerDisplay на уровне сборки. Файл autoexp.cs определяет расширения по умолчанию, используемые Visual Studio для объектов .NET. Вы можете изучить файл autoexp.cs , например, как использовать атрибут DebuggerDisplay, или изменить и скомпилировать файл autoexp.cs, чтобы изменить расширения по умолчанию. Перед изменением файла обязательно создайте резервную копию файла autoexp.cs .
Чтобы создать autoexp.cs, откройте командную строку разработчика для VS2015 и выполните следующие команды.
cd <directory containing autoexp.cs>
csc /t:library autoexp.cs
Изменения вautoexp.dll будут учтены в следующем сеансе отладки.
Использование выражений в 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);
}
}
}
Суффикс ",nq" сообщает вычислителю выражений удалить кавычки при отображении окончательного значения (nq = нет кавычек). Дополнительные сведения о описателях форматирования см. в разделе "Описатели формата" в C#.
Example
В следующем примере кода показано, как использовать DebuggerDisplayвместе с DebuggerBrowsable и DebuggerTypeProxy. При просмотре в окне переменных отладчика, например в окне Наблюдение, создается расширение, которое выглядит следующим образом:
| Name | Value | Type |
|---|---|---|
| Key | "three" | объект {string} |
| Value | 3 | объект {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;
}
}
}
}