How NOT to use dictionaries in .NET Core

Dictionaries are a popular and powerful implementation of the hash table data structure in .NET. Yet, I’ve come across cases where they are used improperly. Maybe strangely is a better word. Some might sound absurd for most of you, so would’ve been for me before I encounter them. Whilst writing the article I couldn’t believe I should make a case against them. At least I hope you’ll find the first two slightly amusing. I want to showcase these encounters here and offer a simple recommendation for each.

Dictionaries (or hash maps) in any programming language have the main benefit of offering quick, in constant complexity time, access to some value based on a key’s hash. You should then consider dictionaries when dealing with large collections of data and/or when needing to associate they key-value couple at runtime whilst subsequently needing to retrieve that value based on a key.

1. As DTOs

This is usually coupled with an enum defining what would be the properties. Below is the bad example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// define the student properties
enum StudentProperty
{
Name,
University
}

// code that creates the student
var student = new Dictionary<StudentProperty, string>
{
{ StudentProperty.Name, "Jean" },
{ StudentProperty.University, "UCLA" },
};

// ...
// code that uses the object
string name = student[StudentProperty.Name];
string university = student[StudentProperty.University];

Considering performance, by using a dictionary you will create an array of keys larger than the values of the enum, you don’t really benefit of the fast retrieval because the number is so small.

Besides that, you have a hard time with (de)serialization and possibly forward mapping. And if you don’t want to do much type casting you can only have the values of the value type in that Dictionary<StudentProperty,string>, here it’s string and you can’t have any ints.

Ditch the dictionary

This must’ve been the case where you forgot about DTOs. A data Data Transfer Object (DTO) only has state (properties) and lacks behavior (no methods). This is useful for contracts between your application layers or external libraries.

Here’s a basic example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// define the student class
class Student
{
public string Name { get; set; }
public string University { get; set; }
}

// code that creates the student
var student = new Student
{
Name = "Scott",
University = "NYU",
};

// ...
// code that uses the object
string name = student.Name;
string university = student.University;

The model for the student is known, the names and types of the properties are know. Using a plain class should be the natural choice, even if it’s for simplicity’s sake.

2. As lists of pairs

Say you need to pass some data around that so happens to have only two attributes. The uses case is just iteration and displaying the data. In a case of a student, the name and the course credits for that year. What collection do you choose. One would say “Well, dictionaries are a collections of key-value pairs, easy-peasy.”, and then would write something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
// code that creates or fetches data in this format
Dictionary<string, int> studentsWithCredits = new Dictionary<string, int>
{
{ "Jean", 28 },
{ "Scott", 25 },
};

// ...
// code that uses that data
foreach(KeyValuePair<string, int> student in studentsWithCredits)
{
Console.WriteLine($"{student.Key}: {student.Value}");
}

Now image you would get some information in a this data format from something a colleague wrote or a third party. Or you skim over this code month later. You’ll ask yourself what does a key represent and what does a value represent. Or suppose you just need a new attribute for the student.

Let’s not ignore the fact that this implementation does not make use of the hash tables fast retrieval characteristic.

Again, ditch the dictionary

What other collection of key-value pairs is out there. Well, a list of such pairs. You could have the generic type be KeyValuePair type, write your own DTO type, but maybe more convenient use named tuples. Therefore the code gets transformed into:

1
2
3
4
5
6
7
8
9
10
11
12
13
// code that creates the data 
List<(string, int)> studentsWithCredits = new List<(string, int)>
{
( "Jean", 28 ),
( "Scott", 25 )
};

// ...
// code that uses that data
foreach((string name, int credits) student in studentsWithGrades)
{
Console.WriteLine($"{student.name}: {student.credits}");
}

Now any consumer knows better what this data is about, just a chain of values. And this is valid for n-values not just pairs. But don’t exaggerate with the n part. I’ve used here the List for the simple showcase type but you may want to take a look at IEnumerable or IReadOnlyCollection to enforce immutability.

3. As Sets

Here I’ll be more brief. In many cases it makes sense to use a dictionary thus I’ll try just to raise some awareness.

When you have some data that needs to be classified into two states only, instead of a Dictionary<T, bool> with boolean values, consider a HashSet. Everything in that set is in one of the states whilst the other fall into the other. The HashSet structure provides constant times for insertion and checking for existence.

Final words

Maybe these usages could be perfectly fine in some circumstances. The point of the article is to make you ask if it’s worth taking the long path when simple and clean ways are here for you.