It is quite desirable to print C# collection contents (Lists, Dictionaries, Sets, etc.) for debugging purposes. Unfortunately, simply calling
ToString() on collection types, prints a less than desirable string. Here is a simple program to print a list.
And here is the output.
So we get the type of the collection, but not the length and elements in it. Let’s go ahead and fix that!
We will start by writing an extension method for the
Now if we replace our new
ToStringExt() method in the initial program, we get this:
ToStringExt: [one, two, three]
Much nicer! But we are not done yet. What if we print a List of Lists? Let’s run the following program:
ToStringExt: [System.Collections.Generic.List`1[System.String], System.Collections.Generic.List`1[System.String]]
The output prints out the top level list, but each sublist is printed using
ToString. That is because our
ToStringExt internally calls
ToString on the list members to print them. To fix that, we can create an specialization of our function to
List type like this:
With this modification, we get this output when we call
ToStringExton a nested list:
ToStringExt: [[one, two], [three, four]]
Nice! This works for nested lists, but what if we had a list of lists of lists? Well we could go down the rabbit hole a few more steps and make specialized overloads of our generic method for 3rd level nested lists, 4th level nested lists and so on! In practice two or three levels is all we need.
We can use the same technique for other collection types. Checkout the github project for this blog post.
An extensible set of extension methods to pretty print (including contents of) collections in C#. …
There I have included additional extension methods for other collection types. For example I support Dictionary, Dictionary of Lists and Dictionary of Dictionaries. You can keep writing these extension methods to be as complex as the data structures of your program. Have a Dictionary of List of HashSets? One extension method will do!
For the sake of completeness, here is the completed class with extension methods for Lists and Dictionaries. It should give you the idea on how to write similar extension methods for other generic collection types.
The main problem is that we need to write more extension methods for deeper, nested collections. Whenever you pretty print a collection and see it prints out the collection type and not the contents, you can add extra extension methods to handle that specific collection type.
Additionally notice that instead of
ToString() we need to call
ToStringExt(). It may not seem like such a big deal, but remember that C# converts any type to
string type through
ToString() method. That’s how expressions like
“name: " + myObjectVariable work. We lose that niceness and need to call our extension method explicitly every time.
Another drawback of using generic methods is that the method call bindings happen at compile time. If we try to pretty print a
List<string> that is stored in an
object variable, it won’t work.
We could fix the problem with inheritance instead of extension methods. We could make sub-classes for all collection types (MyList<T>, MyCollection<K, V>, MyHashSet<T>, etc.), override
ToString() in them and use those classes in our projects. That fix would work flawlessly for deeply nested collections. But it would only work if we don’t use any external libraries. Because as soon as we receive a Collection type from a method we haven’t authored (i.e. a library we are using) we get back to square one and need to convert them to our version of the collections. Unfortunately collections are very common and if we use any external libraries, we will most likely have to deal with them. So this alternative solution has its own drawbacks…
I’ll write another post with a solution using Reflection. The reflection solution can nicely handle any collection type and uses the dynamic (runtime) type of the objects instead of the static type like the solution discussed in this blog post.
Today’s helper methods are very useful for when we know the type of collections we want to print out. In practice most collections are one or two levels deep and the extension methods from this post handle them well enough.
Make sure to checkout the companion github project here to see the complete project and extension methods. You can download and use them in your programs!
Happy pretty printing C# collections!