Можно ли использовать условия в DebuggerDisplay?
Рассмотрим следующий класс:
[DebuggerDisplay("{GetType().Name,nq}: FileName = {FileName,nq}")]
public class FileWrapper
{
public string FileName { get; set; }
public bool IsTempFile { get; set; }
public string TempFileName { get; set; }
}
Я хотел бы добавить отображение отладчика на основе IsTempFileName
имущество. Я хотел бы добавить строку , TempFileName = {TempFileName,nq}
когда экземпляр является временным файлом. Как бы мне этого добиться?
2 ответа
Вы можете использовать условный оператор (?:)
[DebuggerDisplay("{GetType().Name,nq}: FileName = {FileName,nq}{IsTempFile ? \", TempFileName: \" + TempFileName : System.String.Empty,nq}")]
IsTempFile == false
IsTempFile == true
Вы можете использовать любое выражение, которое является допустимым.
Однако имейте в виду, что отладчик будет много оценивать эти выражения, поэтому чем сложнее вы их создаете, тем больше вы заметите снижение скорости отладки (например, при пошаговом выполнении кода).
Еще одна важная вещь, которую следует учитывать, это то, что выражение оценивается отладчиком для языка, использующего класс. Если и класс, и все его потенциальные пользователи находятся в C#, проблем нет, и вы можете использовать такие вещи, как троичный оператор. Однако, если ваш класс также будет использоваться с другого языка, то:
- нет никакой гарантии, что отладчик вообще будет использовать атрибут [DebuggerDisplay],
- если это произойдет, нет гарантии, что он попытается оценить блоки {expression}, и
- есть очень хороший шанс, что он не сможет оценить ваше выражение на C#, если вы начнете делать что-то необычное (например, использовать?:)
Самое безопасное было бы добавить частное свойство для вычисления значения отладчика:
[DebuggerDisplay("{DebugValue,nq}")]
public class FileWrapper {
public string FileName { get; set; }
public bool IsTempFile { get; set; }
public string TempFileName { get; set; }
private string DebugValue {
get {
var text = string.Format("{0}: FileName={1}", this.GetType(), this.FileName);
if (this.IsTempFile)
text += string.Format(", TempFileName={0}", this.TempFileName);
return text;
}
}
}
Это частная собственность, поэтому она не мешает каким-либо потенциальным подклассам.
Во-первых, проголосуйте за "ленивец" раньше моего.... потому что они заставили меня двигаться в правильном направлении.
Во-вторых, вот статья:
Ниже указаны название статьи и автор, на случай, если ссылка выше в будущем умрет.
Настройте отображение объектов в отладчике Visual Studio ПО ВАШЕМУ
Лесли Ричардсон
Программный менеджер, отладка и диагностика Visual Studio
В-третьих, вот немного более общий пример, основанный на пустой или ненулевой дочерней коллекции:
[System.Diagnostics.DebuggerDisplay("ParentName = '{ParentName}', MyKidsCount='{null == MyKids ? 0 : MyKids.Count}'")]
public class MyParent
{
public string ParentName { get; set; }
public ICollection<MyKid> MyKids { get; set; }
}
Вы можете использовать его с методом Extensions.
using System;
using System.Linq;
using System.Diagnostics;
using System.ComponentModel;
namespace ConsoleApplicationDebuggerDisplay
{
class Program
{
static void Main(string[] args)
{
MyObject o1 = new MyObject();
MyObject o2 = new MyObject();
o1.Items = new int[] { 1, 2, 3, 4 };
}
}
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class MyObject
{
[DebuggerDisplay("{Items.ToDebuggerDisplay(),nq}")]
public int[] Items { get; set; }
[DebuggerBrowsable(DebuggerBrowsableState.Never), Browsable(false)]
internal string DebuggerDisplay
{
get
{
return string.Format("{{Items={0} ...}}"
, Items.ToDebuggerDisplay()
);
}
}
}
internal static class Extensions
{
public static bool IsNull(this object o)
{
return object.ReferenceEquals(o, null);
}
public static bool IsNotNull(this object o)
{
return !object.ReferenceEquals(o, null);
}
public static string ToDebuggerDisplay<T>(this System.Collections.Generic.IEnumerable<T> items)
{
if (items.IsNull())
return "null";
return string.Format("{{Count={0}}}", items.Count());
}
}
}