具有“如果键不在字典中则添加新值”的多维字典

Tom*_*ora 5 c# dictionary initialization

SO上也有类似的问题,但没有一个回答我的问题。

我想要一个二维词典来翻译。像这样的东西:

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";
Run Code Online (Sandbox Code Playgroud)

如果我使用传统字典就好了Dictionary<string,Dictionary<TranslationKeys,string>>

但我不想以这样的“丑陋”方式初始化它:

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

但像这样:

Dictionary["PL"][TranslationKeys.SubTitle] = "Subtitle in Polish";
Run Code Online (Sandbox Code Playgroud)

所以我尝试实现一个“智能”多维字典,如果他得到了值,它就会自行计算出来。到目前为止我所做的是一个使用 Dictionary 和特殊索引器的新通用类:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但现在我陷入了困境......因为我在通用类型 TranslateDictionary 中使用字符串,所以我得到了这个错误:

错误 2“string”必须是具有公共无参数构造函数的非抽象类型,才能将其用作泛型类型或方法“Resources.TranslateDictionary”中的参数“TValue”

尽管编译器不会抱怨这样的初始化:

Dictionary["EN"][TranslationKeys.Title] = "Title in English";
Run Code Online (Sandbox Code Playgroud)

也许我应该使用其他类型的集合而不是我不知道的字典来解决我的问题?

Tom*_*ora 5

我做到了。我只需要稍微改变我的索引器。以下是实现此功能的方法:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在当你有

TranslateDictionary<string, TranslateDictionary<TranslationKeys, string>> Dictionary { get; set; }
Run Code Online (Sandbox Code Playgroud)

您只需要创建一个字典实例:

Dictionary = new TranslateDictionary<string, TranslateDictionary<TranslationKeys, string>>();
Run Code Online (Sandbox Code Playgroud)

您可以自由地初始化它的元素,如下所示:

Dictionary["PL"][TranslationKeys.SubTitle] = "SubTitle in Polish";
Dictionary["EN"][TranslationKeys.SubTitle] = "SubTitle in English";
Dictionary["DE"][TranslationKeys.SubTitle] = "SubTitle in German";
Run Code Online (Sandbox Code Playgroud)

也许这种方法比普通字典慢,因为每次尝试读取值时都会检查内部字典是否包含键,但至少你可以以“更干净”的方式为其分配元素。

更新 我稍微升级了我的 TranslateDictionary。我添加了布尔属性“Initialized”。现在,初始化后,我可以将此值设置为“true”,并且不会再检查字典中是否存在该值。然后它的行为将更像普通的词典类型。

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)