深层嵌套词典是反模式吗?

时间:2012-02-16 00:34:47

标签: c# oop data-structures dictionary

我有一个可以使用三深嵌套字典很容易表示的结构,如此

private static Dictionary<string, Dictionary<string, Dictionary<string,string>>> PrerenderedTemplates;

结构可能会像这样使用

PrerenderedTemplates[instanceID][templategroup][templatepart]

现在,我意识到这段代码很难阅读,因为从查看定义语句来看,你无法分辨出它的用途。我将其更改为Dictionary<string, PrerenderedTemplate>时唯一可以看到的优点是可读性。将每个嵌套转换为自己的类(例如class PrerenderedTemplate{} class TemplateGroup{} class TemplatePart{})将为很少(如果有的话)计算优势添加更多代码行。据我所见。

  • 那么,我的方法是“好的”还是我应该加倍努力并创建单独的课程?
  • 是否可以在文档/评论
  • 中介绍嵌套Dictionary的工作原理
  • 处理这种嵌套是否有最佳做法?
  • 请记住,这是一个私人会员,对于使用该课程的人来说,不需要直截了当。

更新

所以,在Reza的启发下,但是无法使用Tuples,我决定创建自己的密钥生成器并实现他的模式:

private Dictionary<string, string> PrerenderedTemplates;
private string GetPrerenderedTemplateKey(string InstanceId, string FeatureId, string OptionId)
{
    return new StringBuilder(instanceId)
    .Append(FormatTools.LIST_ENTRY_DELIMITER)
    .Append(templategroup)
    .Append(FormatTools.LIST_ENTRY_DELIMITER)
    .Append(templatepart).ToString();
}

其中FormatTools.LIST_ENTRY_DELIMITER是Unicode私人使用字符0xe04d

3 个答案:

答案 0 :(得分:16)

我提供另一种选择:

Dictionary<Tuple<string, string, string>, string> pt;

访问字典:

pt[Tuple.Create("id","group","part")]
  

<强>更新

C#7 中引入的

Value Tuples 最引人注目:

Dictionary<(string id, string group, string part), string> pt;

访问字典:

pt[("id", "group", "part")]

答案 1 :(得分:1)

我会创建一个自定义词典。像这样的东西

public class TrippleKeyDict
{
    private const string Separator = "<|>";
    private Dictionary<string, string> _dict = new Dictionary<string, string>();

    public string this[string key1, string key2, string key3]
    {
        get { return _dict[GetKey(key1, key2, key3)]; }
        set { _dict[GetKey(key1, key2, key3)] = value; }
    }

    public void Add(string key1, string key2, string key3, string value)
    {
        _dict.Add(GetKey(key1, key2, key3), value);
    }

    public bool TryGetValue(string key1, string key2, string key3, out string result)
    {
        return _dict.TryGetValue(GetKey(key1, key2, key3), out result);
    }

    private static string GetKey(string key1, string key2, string key3)
    {
        return String.Concat(key1, Separator, key2, Separator, key3);
    }
}

如果您认为,连接字符串不够安全,因为密钥可能包含分隔符,然后使用您自己的密钥类型或Touple<string,string,string>作为密钥。由于此实现细节隐藏在自定义词典中,因此您可以随时对其进行更改。

您可以像这样使用字典

var dict = new TrippleKeyDict();

// Using the Add method
dict.Add(instanceID, templategroup, templatepart, "some value");

// Using the indexer
dict[instanceID, templategroup, templatepart] = "xy";
string result = dict[instanceID, templategroup, templatepart];

// Using the TryGetValue method
if (dict.TryGetValue(instanceID, templategroup, templatepart, out result)) {
    // Do something with result
}

答案 2 :(得分:0)

我想提供一种替代方法,使用 SortedDictionary 和自定义比较器:

    public class PrerenderedTemplate
    {
        public string instanceID;
        public string templategroup;
        public string templatepart;

        public PrerenderedTemplate(string id, string tempGroup, string tempPart)
        {
            instanceID = id;
            templategroup = tempGroup;
            templatepart = tempPart;
        }

        // custom comparer instance used as argument 
        // to SortedDictionary constructor
        public class Comparer : IComparer<PrerenderedTemplate>
        {
            public int Compare(PrerenderedTemplate x, PrerenderedTemplate y)
            {
                int compare = 0;
                if (compare == 0) compare = x.instanceID.CompareTo(y.instanceID);
                if (compare == 0) compare = x.templategroup.CompareTo(y.templategroup);
                if (compare == 0) compare = x.templatepart.CompareTo(y.templatepart);
                return compare;
            }
        }
    }

像这样使用:

    var dictionary = new SortedDictionary<PrerenderedTemplate, string>(new PrerenderedTemplate.Comparer());

    dictionary.Add(new PrerenderedTemplate("1", "2", "3"), "123");
    dictionary.Add(new PrerenderedTemplate("4", "5", "6"), "456");
    dictionary.Add(new PrerenderedTemplate("7", "8", "9"), "789");

    Assert.AreEqual<string>(dictionary[new PrerenderedTemplate("7", "8", "9")], "789");

RezaArab 的回答是合适的,但我个人不喜欢Tuples基于他们的模糊属性和冗长的语法。

如果任何要求发生变化,带有比较器的自定义类可提供更高的清晰度和灵活性。