4

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

I want to have two dimensional dictionary for translation. Something like this:

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 OK if i use traditional dictionary like Dictionary<string,Dictionary<TranslationKeys,string>>

But i don't want to initialize it in "ugly" way like this:

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've tried to implement an "intelligent" multidimensional dictionary that would figure out itself if he got the value or not. What I've done this far is a new generic class that uses Dictionary and special indexer:

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'm using strings in my generic typed TranslateDictionary i'm gettint this error:

Error 2 'string' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TValue' in the generic type or method 'Resources.TranslateDictionary'

Allthough compiler doesn't complain about initialization like this:

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

Maybe i should use other type of collection instead of Dictionary that i'm not aware of, to solve my problem?

Tomasz Sikora
  • 1,649
  • 3
  • 19
  • 30

1 Answers1

4

I did it. I just had to slightly change my indexer. Here is the way to make this work:

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 when you have

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

You just need to create an instance of the dictionary:

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

And you are free to initialize it's elements like this:

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

Maybe this approach is slower than normal dictionary because of checking if the inner dictionary contains key every time when you try to read value, but at least you can assign elements to it in "cleaner" way.

UPDATE I've upgraded my TranslateDictionary a little. I've added boolean property "Initialized". Now after initialization i can set this value to "true" and there won't be no more checking if value exists in dictionary. And it will act then more like normal Dictioanry type.

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;
        }
    }
}
Tomasz Sikora
  • 1,649
  • 3
  • 19
  • 30