Multidimensional dictionary with "add a new value if the key is not in the dictionary"

There were similar questions on SO, but none of them answered my question.

I want to have a two-dimensional dictionary for translation. Something like that:

Dictionary["DE"][TranslationKeys.Title] = "Title in German"; Dictionary["DE"][TranslationKeys.SubTitle] = "Subtitle in German"; Dictionary["PL"][TranslationKeys.Title] = "Title in Polish"; Dictionary["PL"][TranslationKeys.SubTitle] = "Subtitle in Polish"; Dictionary["EN"][TranslationKeys.Title] = "Title in English"; Dictionary["EN"][TranslationKeys.SubTitle] = "Subtitle in English"; 

which is fine if I use a traditional dictionary, for example Dictionary<string,Dictionary<TranslationKeys,string>>

But I do not want to initialize it in an "ugly" way as follows:

 Dictionary = new Dictionary<string,Dictionary<TranslationKeys,string>>(){ {"PL",new Dictionary<TranslationKeys,string>(){{TranslationKeys.SubTitle,"Subtitle in Polish"}}} }; 

but like this:

 Dictionary["PL"][TranslationKeys.SubTitle] = "Subtitle in Polish"; 

So, I tried to introduce an “intelligent” multidimensional dictionary, which would understand whether it got meaning or not. What I have done so far is a new generic class that uses a dictionary and a special index:

 public class TranslateDictionary<TKey, TValue> where TValue : new() { private Dictionary<TKey, TValue> Dictionary; public TValue this[TKey lang] { get { if (!Dictionary.ContainsKey(lang)) { TValue obj = new TValue(); Dictionary.Add(lang, new TValue()); } return Dictionary[lang]; } set { Dictionary[lang] = value; } } } 

But now I'm stuck ... Because I use strings in my typical typed TranslateDictionary, I get this error:

Error 2 "string" must not be an abstract type with an open constructor without parameters in order to use it as a parameter "TValue" in the generic type or method "Resources.TranslateDictionary"

The Allthough compiler does not complain about initialization as follows:

 Dictionary["EN"][TranslationKeys.Title] = "Title in English"; 

Maybe I should use a different type of collection instead of a dictionary that I don't know about to solve my problem?

+4
source share
1 answer

I have done it. I just had to slightly change my index. Here's how to do it:

 public class TranslateDictionary<TKey, TValue> { private Dictionary<TKey, TValue> Dictionary = new Dictionary<TKey,TValue>(); public TValue this[TKey lang] { get { if (!Dictionary.ContainsKey(lang)) { Dictionary.Add(lang, Activator.CreateInstance<TValue>()); } return Dictionary[lang]; } set { Dictionary[lang] = value; } } } 

Now that you have

 TranslateDictionary<string, TranslateDictionary<TranslationKeys, string>> Dictionary { get; set; } 

You just need to instantiate the dictionary:

 Dictionary = new TranslateDictionary<string, TranslateDictionary<TranslationKeys, string>>(); 

And you can initialize such elements as follows:

 Dictionary["PL"][TranslationKeys.SubTitle] = "SubTitle in Polish"; Dictionary["EN"][TranslationKeys.SubTitle] = "SubTitle in English"; Dictionary["DE"][TranslationKeys.SubTitle] = "SubTitle in German"; 

Perhaps this approach is slower than a regular dictionary due to checking that the internal dictionary contains a key every time you try to read a value, but at least you can assign it a cleaner element.

UPDATE I updated my TranslateDictionary a bit. I added the boolean property “Initialized”. Now after initialization, I can set this value to true and will no longer check if the value exists in the dictionary. And he will then act more like the usual type of Dictioanry.

 public class TranslateDictionary<TKey, TValue> { public bool Initialized { get; set; } private Dictionary<TKey, TValue> Dictionary = new Dictionary<TKey,TValue>(); public TValue this[TKey lang] { get { if (!Initialized) { if (!Dictionary.ContainsKey(lang)) { Dictionary.Add(lang, Activator.CreateInstance<TValue>()); } } return Dictionary[lang]; } set { Dictionary[lang] = value; } } } 
+3
source

Source: https://habr.com/ru/post/1486361/


All Articles