Упрощаем просмотр значений переменной в отладке
Знаете ли вы об атрибутах, способных облегчить отладку .NET приложений?
[DebuggerDisplay]
Этот атрибут позволяет отобразить значения ключевых свойств экземпляра класса вместо типа в окнах Watch. Для этого необходимо добавить его в описание класса, указав имена этих свойств в фигурных скобках в качестве параметра. Например:
[DebuggerDisplay("{Date} => {Value}")]
internal class ChartPoint
{
public DateTime Date { get; set; }
public float Value { get; set; }
public string Hint { get; set; }
}
И тогда вместо стандартного

отладчик покажет следующее:

Кроме того, такое решение удобно для перечислений. Например:

[DebuggerBrowsable]
Еще один атрибут, определяющий как будет выглядеть значение в окне отладчика. Позволяет определить три состояния, определенных в перечислении DebuggerBrowsableState:
- Never – не показывать элемент (полезен при создании библиотечных классов и компонент);
- Collapsed – показывать свернутым (поведение по умолчанию);
- RootHidden – не показывать сам элемент, но показывать содержащуюся в нем коллекцию.
Посмотрим пример:
internal class ChartData
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int _chartId;
public string Title { get; set; }
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public ChartPoint[] Points { get; set; }
}
В данном случае, поле _chartId не будет отображено в окне отладчика, а точки Points будут показаны сразу на уровне экземпляра. Обратите внимание, что [DebuggerDisplay] по прежнему сразу отображает текущие значения:

[DebuggerStepThrough]
DebuggerStepThroughAttribute позволяет указать метод, в который отладчик не должен заходить в пошаговом режиме. Однако он не запрещает установку внутри точек останова, которые сработают. При этом опция отладчика “Just My Code” должна быть включена.
[DebuggerHidden]
Этот атрибут полностью скрывает элемент от отладчика. Использование его со свойством аналогично [DebuggerBrowsable(DebuggerBrowsableState.Never)]. При указании его для метода, отладчик в пошаговом режиме не только проигнорирует сам метод, но и установленные внутри точки останова.
[DebuggerTypeProxy]
DebuggerTypeProxyAttribute позволяет задать объект, который будет использоваться для отображения данных экземпляра в отладке. Это позволяет кардинально изменить вид объекта в отладчике.
Прокси это обычный класс. Единственное условие – параметром его его конструктора должен быть экземпляр исходного типа. Например, с помощью данной техники выведем для ChartData максимальную дату и среднее значение:
internal class ChartDataDebugView
{
private readonly ChartData _chartData;
public ChartDataDebugView(ChartData chartData)
{
this._chartData = chartData;
}
public DateTime MaxDate
{
get { return this._chartData.Points.Max(p => p.Date); }
}
public float AveraveValue
{
get { return this._chartData.Points.Average(p => p.Value); }
}
}
[DebuggerTypeProxy(typeof(ChartDataDebugView))]
[DebuggerDisplay("{Title}")]
internal class ChartData
{
private int _chartId;
public string Title { get; set; }
public ChartPoint[] Points { get; set; }
}
Результатом будет следующий вид при отладке:
Ссылка Raw View позволяет посмотреть оригинальный экземпляр. Также обратите внимание, что [DebuggerDisplay] в данном случае работает с свойствами исходного типа.
[DebuggerVisualizer]
И в завершении, стоит упомянуть еще один атрибут – DebuggerVisualizerAttribute, который позволяет указать собственный класс для отображения текущих значений. В данном случае весь вывод информации, включая окна для отображения, полностью ложиться на разработчика.
Для упрощения этой задачи можно использовать абстрактный базовый класс DialogDebuggerVisualizer, реализующий окно вывода. В этом случае, необходимо переопределить его метод Show() для отображения информации. Простейшую реализацию такого подхода можно посмотреть в MSDN.