C# – Should Nested Generic Collections Be Avoided?

ccollectionsgenerics

I recently came across a dictionary with lists for values passed as an argument:

Demo(Dictionary<string, List<string>> arg)

It got me thinking—normally I would abstract any list or array to an IEnumerable with the same element type. Similarly, a specific dictionary could be abstracted to IDictionary. But a nested construction, as far as I am aware, can not be abstracted, as it is uncertain in terms of variance and can't be casted to:

IDictionary<string, <IEnumerable<string>>

Are there any other reasons to avoid nested generics? Or am I using them wrong? Does this use-case warrant a separate class?

Best Answer

Probably

There are different use cases as well as different schools of thought in programming.

However, from my experience, I never regretted putting a collection of things into its own class. It allows you to restrict access in the way the collection is meant to be used, plus you can name those "access points" (= methods, properties etc).

Why not only LINQ

Sure, with LINQ you can easily filter, sort, remove all elements that have condition x etc, but if you create a class containing the collection (private-ly), you can restrict the class to only do that a certain way. For example, you can provide a standard way of filtering. This is basically the OOP concept of encapsulation.

Encapsulation is an object-oriented programming concept that binds together the data and functions that manipulate the data, and that keeps both safe from outside interference and misuse.

By the way, I'm not advocating against LINQ, because it's amazing. The LINQ queries just tend to end up in a method on my "collection classes' and look a lot like what Martin Fowler advises in this regard. It's a long article, but the first example is enough to demonstrate what I mean:

static public IEnumerable<String> TwitterHandles(IEnumerable<Author> authors, string company) {
return authors
  .Where(a => a.Company == company)
  .Select(a => a.TwitterHandle)
  .Where (h => h != null);
}

Advice: Encapsulate collections

Essentially, an own class ArgumentList can provide additional functionality, while it doesn't take anything away. Whatever you intend to use, you can expose - whatever you don't intend to be used can't even be used.

This also means you now only have to care about ArgumentList's interface and not about its implementation. I had my fair share of cases where such a "collection class" made it obvious that I didn't actually need a Dictionary<> and a List<> was enough. Furthermore, it was then also easy to change it to a List<> because I only needed to change the collection class itself - just replace the collection and adjust the code in the methods so they still do what they say.

Now as a summary of all that, IDictionary<string, ArgumentList> looks better than your given example, but in a way that's only a symptom of something bigger.

PS

That being said, I do have a part in my current code base that uses collections similar to your example. Because it's "just shifting some data around until it fits". However, every other place where I used a "collection class", the code is way easier to understand and I'm considering changing this part, too. You know, when I have the time :D

Also, in case you use IoC containers, "collection classes" are more injection friendly than bare-bones collections.

I'd advise you to read the question and accepted answer here. It's not a duplicate or even a similar question, but the accepted answer has quite some overlap in information. It's a very nice explanation of how collections are meant to be used in C#, by one of C#'s creators no less - it definitely was a bit of an aha moment for me.