How to make [DebuggerDisplay] respect inherited classes or at least work with collections?
Asked Answered
D

3

14

I've got a class which inherits from a List<MagicBean>. It works well and as expected in all respects except one: when I add the [DebuggerDisplay] attribute. Even though looking at List has its as [DebuggerDisplay("Count = {Count}")], if I so much as copy and paste that onto mine, I lose the ability to look directly at all of the MagicBeans I have without drilling into base->private members while debugging.

How do I get the best of both worlds? IE: Custom value in the value column, and Visual Studio not hiding my magic beans from me?

Deflower answered 8/7, 2009 at 20:59 Comment(0)
L
13

You can get the effect you need by using the DebuggerTypeProxy attribute. You need to create a class to make a debug "visualisation" of your inherited list:

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

You can then declare this class to be used by the debugger for displaying your class, along with the DebuggerDisplay attribute:

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

This will give you the "Count = 3" message when you hover over an instance of your inherited list in Visual Studio, and a view of the items in the list when you expand the root node, without having to drill down into the base properties.

Using ToString() to specifically get debug output is not a good approach, unless of course you are already overriding ToString() for use in your code elsewhere, in which case you can make use of it.

Lucianolucias answered 8/7, 2009 at 23:26 Comment(2)
Nifty, is useful, but seems pretty copy and paste. I can't test right now, but is there some way I can use the code List already uses, or in the very least be able to write a generic version once? I'd hate to type this for every custom container class.Deflower
After going through some digging, apparently the answer is no.Deflower
M
2

After looking at the "Using DebuggerDisplay Attribute" article on MSDN, they suggest that you could override the ToString() function of your class as an alternate option rather than using DebuggerDisplay attribute. Overriding the ToString() method won't hide your beans either.

If a C# object has an overridden ToString(), the debugger will call the override and show its result instead of the standard {}. Thus, if you have overridden ToString(), you do not have to use DebuggerDisplay. If you use both, the DebuggerDisplay attribute takes precedence over the ToString() override.

Are you able to override the ToString() method on your class or are you using it for other purposes?

I don't know if you've already considered this or not, but I thought I'd suggest it just incase it helps. :-)

For completeness so anyone else can quickly mock it up; here's a quick example that I made:

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; }
    }    
}
Mucous answered 8/7, 2009 at 22:1 Comment(0)
U
-1

Use the DebuggerDisplay attribute like so:

[DebuggerDisplay("ID:{ID},Customers:{Customers==null?(int?)null:Customers.Count}")]`
class Project
{
    int ID{get;set;}
    IList<Customer> Customers{get;set;}
}
Uziel answered 15/8, 2016 at 13:54 Comment(2)
This answer in in the "low quality answers queue".Sannyasi
For reference: This answer fails to disclose that the URL below it is the author's. See How not to be a spammer.Melliemelliferous

© 2022 - 2024 — McMap. All rights reserved.