Granville Barnett

Debug proxies for custom collections to aide debugging in Visual Studio

I stumbled across this while working on a small project (Data Structures and Algorithms (DSA)).  Creating a proxy for a type, or whatever really - in my case a collection is really simple and provides some really cool results in the locals window when debugging.

Raw View

The raw view is exactly what it implies, a no holds barred view of of type you are displaying in the locals window.  The raw view by default is not expanded, instead you have a small amount of information about a particular object.

vis1

Building a Customized View

This is really simple, especially for my scenario.  In the previous image you saw that Raw View was a child node of the myQueue node.  The direct children of myQueue shows a simplified view of the collection in hand, i.e. it shows it's items in what appears to be an array based format - that is that it starts at 0 and goes from there.  This is in fact an array.

The following is the type used for the proxy (this is actually the same as used for the collection in the BCL):

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Dsa {

    internal sealed class CollectionDebugView<T> {

        private ICollection<T> _collection;

        public CollectionDebugView(ICollection<T> collection) {
            if (collection == null) {
                throw new ArgumentNullException("collection");
            }
            _collection = collection;
        }

        [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
        public T[] Items {
            get {
                T[] items = new T[_collection.Count];
                _collection.CopyTo(items, 0);
                return items;
            }
        }

    }

}

This debug proxy is designed to work on any collection that implements the ICollection(Of T) interface.  The array like representation of the items in the collection I spoke about earlier are retrieved from the public property Items.

Note:  any public properties that have getters will be visible in the locals window.

There are a few final steps that you need to go ahead and do if you want to provide this rich debug experience for your customers and that lies within the use of a few attributes.

[DebuggerDisplay("Count={Count}")]
[DebuggerTypeProxy(typeof(CollectionDebugView<>))]

The first attribute is what makes the count of the items appear level with the collection object name, Count is a property that is a member of the ICollection(Of T) interface.

The second DebuggerTypeProxyAttribute is what utilizes our debug proxy - when you expand the custom collection node we use the proxy to define what should be shown initially to the developer, the Raw View becomes a child of that simplified view.  The type of the CollectionDebugView type is, like all generics determined at run time (unlike C++ which is compile time) - as we can't explicitly say what type the user will be creating a collection of we use the empty <>.

Comments

No Comments