Как заставить [DebuggerDisplay] уважать унаследованные классы или, по крайней мере, работать с коллекциями?

У меня есть класс, который наследуется от List<MagicBean>. Он работает хорошо и, как ожидается, во всех отношениях, кроме одного: когда я добавляю атрибут [DebuggerDisplay]. Несмотря на то, что просмотр списка имеет [DebuggerDisplay("Count = {Count}")], если я так же копирую и вставляю его в свою, я теряю возможность смотреть прямо на все MagicBeans, которые у меня есть, без сверления в base- > private членов при отладке.

Как я могу получить лучшее из обоих миров? IE: пользовательское значение в столбце значений, а Visual Studio не скрывает от меня мою магию beans?

Ответы

Ответ 1

Вы можете получить необходимый эффект, используя атрибут DebuggerTypeProxy. Вам нужно создать класс для отладки "визуализации" вашего унаследованного списка:

internal sealed class MagicBeanListDebugView
{
    private List<MagicBean> list;

    public MagicBeanListDebugView(List<MagicBean> list)
    {
        this.list = list;
    }

    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
    public MagicBean[] Items{get {return list.ToArray();}}
}

Затем вы можете объявить этот класс для использования отладчиком для отображения вашего класса вместе с атрибутом DebuggerDisplay:

[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(MagicBeanListDebugView))]
public class MagicBeanList : List<MagicBean>
{}

Это даст вам сообщение "Count = 3" при наведении курсора на экземпляр вашего унаследованного списка в Visual Studio и представление элементов в списке при расширении корневого node без необходимости сверления вниз в базовые свойства.

Использование ToString() для получения результата отладки не является хорошим подходом, если, конечно, вы уже не переопределяете ToString() для использования в вашем коде в другом месте, и в этом случае вы можете его использовать.

Ответ 2

Посмотрев на статью Using DebuggerDisplay Attribute в MSDN, они предлагают переопределить функцию ToString() вашего класса как альтернативный вариант, а не использовать атрибут DebuggerDisplay. Переопределение метода ToString() не скроет ваш beans.

Если объект С# переопределен ToString(), отладчик вызовет переопределить и показать результат стандартного {}. Таким образом, если вы переопределили ToString(), вы делаете не нужно использовать DebuggerDisplay. Если вы используете оба варианта, DebuggerDisplay атрибут имеет приоритет над ToString() переопределяет.

Можно ли переопределить метод ToString() в вашем классе или использовать его для других целей?

Я не знаю, считали ли вы это или нет, но я подумал, что предлагаю ему просто помочь.: -)

Для полноты, чтобы кто-нибудь еще мог быстро издеваться над этим; вот быстрый пример, который я сделал:

namespace StackOverflow
{
    //broken BeanPouch class that uses the DebuggerDisplay attribute
    [System.Diagnostics.DebuggerDisplay("Count = {Count}")]
    class BrokenBeanPouch : List<MagicBean>
    { }

    //working BeanPouch class that overrides ToString
    class WorkingBeanPouch : List<MagicBean>
    {
        public override string ToString()
        {
            return string.Format("Count = {0}", this.Count);
        }
    }

    class Program
    {
        static WorkingBeanPouch myWorkingBeans = new WorkingBeanPouch()
        {
            new MagicBean() { Value = 4.99m }, new MagicBean() { Value = 5.99m }, new MagicBean() { Value = 3.99m }
        };

        static BrokenBeanPouch myBrokenBeans = new BrokenBeanPouch()
        {
            new MagicBean() { Value = 4.99m }, new MagicBean() { Value = 5.99m }, new MagicBean() { Value = 3.99m }
        };

        static void Main(string[] args)
        {
            //break here so we can watch the beans in the watch window
            System.Diagnostics.Debugger.Break();
        }
    }

    class MagicBean
    {
        public decimal Value { get; set; }
    }    
}

Ответ 3

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

[DebuggerDisplay("ID:{ID},Customers:{Customers==null?(int?)null:Customers.Count}")]`
class Project
{
    int ID{get;set;}
    IList<Customer> Customers{get;set;}
}

Дополнительная информация здесь.