Pretty Printing C# Collections with Generic Extension Methods

No Such Dev
4 min readFeb 19, 2020

--

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.

System.Collections.Generic.List`1[System.String]

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 List class:

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:

ToString:System.Collections.Generic.List`1[System.Collections.Generic.List`1[System.String]]
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.

Other Collections

We can use the same technique for other collection types. Checkout the github project for this blog post.

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 Drawbacks

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.

Alternate Solutions

Inheritance

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…

Reflection

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.

End Note

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!

--

--

No Such Dev
No Such Dev

Written by No Such Dev

Software Engineer | Indie Game Developer | Founder of No Such Studio. Follow me to learn how to make video games with Unity. http://www.nosuchstudio.com

No responses yet