Give names to Key and Value in C# Dictionary to improve code readability

In C# struct, we can know clearly the purpose of a variable by it's name. For example,



public struct Book
{
public string title;
public string author;
}


Then, i know b.title is a type of string and it's referring to title.



However in C# dictionary, we can only specify the type



Dictionary<string,string> d


How can i make the code more readable such that the key of the dictionary is type of string and it is referring to title, and the value is type of string and it is referring to author? That means, other people can easily know that d["J.R.R. Tolkien"] is a wrong use of the dictionary when reading the code.



EDIT
@mike z suggested to use a variable name titleToAuthor to help readability. But my real issue is that in the code there are nested dictionary. E.g.



Dictionary<string, Dictionary<string, string>>, 
or even 3 levels
Dictionary<string, Dictionary<string , Dictionary< string , string[] >>>.


We want to keep to convenience of using Dictionary without creating our own class but at the same time we need some way to improve the readability



Answers

What you can't solve without fighting the language, I'd suggest solving with documentation. Identifiers are included in that category as a form of self-documentation.



So to add self-documentation to a type of this sort:



using TitleToAuthor = System.Collections.Generic.Dictionary<
string, // title
string // author
>;


To add self-documentation to instances of that type:



TitleToAuthor title_to_author = new TitleToAuthor();


Unfortunately you cannot nest using directives as generic type parameters, so using a solution like this will make your using directives at the top of the file butt-ugly, but at least that butt-ugly code, written once, will then create a very readable alias to the left of it (showing exactly what it's for) that you can refer to throughout the rest of the code without actually creating new data types.



Another way is to simply create new data types, inheriting from Dictionary, e.g. I'd suggest this route if you have more you can do with the new type than simply getting a more readable type name, like adding methods that are specifically useful for that collection or if that collection is used in many source files (since then you'd have to repeat the same using directives a lot).



In such a case, composition might be better than inheritance (storing dictionary as a member) since then you could create a smaller, subset interface tailored to your needs (and perhaps with fewer ways to misuse it by only providing higher-level functions that make total sense for the specific container type) instead of just a full-blown dictionary's interface + more methods. In such a case, you'd be turning that somewhat hard-to-read, generic, general-purpose dictionary into a hidden implementation detail of something that not only reads better with respect to its type name, but also provides a smaller, tailored (less general) interface that more specifically handles your needs. For a simple example, it might be an error to allow empty strings to be specified for the key or the value. A dictionary doesn't impose such assertions, but an interface of your own design that uses dictionary as a private implementation detail can.



If you're tripping up over the readability of the key/value parameters of a dictionary, perhaps the problem is not really in the readability of the dictionary, but in the amount of public exposure that specific dictionary has. If you have a dictionary instance or even type with very public visibility that gets referred to all over the place, then you might be concerned with not only the readability of such code but also the flexibility that allows those accessing it to do anything they want that's allowed in a full-blown dictionary (including things you might not want to allow to happen at a broader scope). After all, even a type like float tells you very little about what it's supposed to do, but we tend to write code in a way where floats are either implementation details of a class/function or just function parameters/return types that are rather obvious in terms of what they do. So perhaps it would be better to seek to make such dictionaries less visible and more into private implementation details, since the clarity and readability of implementation details generally doesn't matter nearly as much as the more publicly-visible parts of an interface that are going to be accessed throughout your codebase.



Answers

By design, a dictionary is a key-value pair, and the exposed collections are called as such. If you want something more explicit, you can derive your own custom dictionary or implement the appropriate dictionary interfaces on your own class. You could also look at implementing this as a keyed collection, where you provide a lambda expression to derive the key from your data.



Answers

As suggested by @ScottDorman you could define a new Type TitleAuthorDictionary that derives from Dictionary<string, string>, like so:



public class TitleAuthorDictionary : Dictionary<string, string>
{
public new void Add(string title, string author)
{
base.Add(title, author);
}

public new string this[string title]
{
get { return base[title]; }
set { base[title] = value; }
}
}


You could then use the more readable Dictionary Collection, like this:



TitleAuthorDictionary dictionary = new TitleAuthorDictionary();
dictionary.Add("Title1", "Author1");
dictionary.Add(title: "Title2", author: "Author2");
dictionary["Title2"] = "Author3";