是否可以优化此代码?

时间:2014-08-20 10:41:44

标签: winforms c#-4.0 recursion linq-to-objects lambda

我必须在WinForm中显示一个基于复杂字典的TreeView,我正在寻找“最短”的方法来实现它。我认为它可以在一个LINQ查询中完成,但我不知道如何,我甚至不确定它是否可能。

这是一个输入字典的例子:

Dictionary<String, String> dict = new Dictionary<String, String>()
{
  {"aaa.bbb.ccc.ddd", "value1"},
  {"aaa.bbb.ccc.eee", "value2"},
  {"aaa.bbb.fff.ggg", "value3"},
  {"aaa.hhh.iii.jjj", "value4"},
  {"bbb.ddd", "value5"},
  {"ccc", "value6"}
};

我想回到这样的TreeView:

|--+ aaa
|  |--+ bbb
|  |  |--+ ccc
|  |  |  |--- ddd = value1
|  |  |  |--- eee = value2
|  |  |
|  |  |--+ fff
|  |  |  |--- ggg = value3
|  |
|  |--+ hhh
|  |  |--+ iii
|  |  |  |--- jjj = value4
|
|--+ bbb
|  |--- ddd = value5
|
|--+ ccc = value6

这就是我现在所拥有的(我还没有处理价值):

List<String> list = new List<string>() { 
    "aaa.bbb.ccc.ddd", 
    "aaa.bbb.ccc.eee",
    "aaa.bbb.fff.ddd",
    "aaa.bbb.fff.ggg",
    "aaa.ggg.fff.hhh",
    "hhh.iii.jjj.kkk"
};

Action<TreeNode, String> traverse = null;

traverse = (node, chaine) =>
{
    String[] tab = chaine.Split(new char[] { '.' }, 2);

    TreeNode child = null;
    if (node.Nodes.ContainsKey(tab[0]))
    {
        child = node.Nodes[tab[0]];
    }
    else
    {
        child = node.Nodes.Add(tab[0]); // + ((tab.Length > 1) ? " - " + tab[1] : ""));
        child.Name = tab[0];
    }

    if (tab.Length > 1 && !String.IsNullOrEmpty(tab[1]))
        traverse(child, tab[1]);
};

TreeNode test = this.treeView1.Nodes.Add("test");

list.ForEach(x => traverse(test, x));

我希望我的解释清楚。

1 个答案:

答案 0 :(得分:1)

你的Action中有相当多的逻辑,所以我怀疑它可以在一个LINQ查询中完成,所以它看起来像

var query = from this in that where this is t select this

但你可以做的是重写一下,例如:

    public void AnotherWay()
    {
        TreeNode parent = this.treeView1.Nodes.Add("test");

        List<String> list = new List<String>() 
        { 
            "aaa.bbb.ccc.ddd", 
            "aaa.bbb.ccc.eee",
            "aaa.bbb.fff.ddd",
            "aaa.bbb.fff.ggg",
            "aaa.ggg.fff.hhh",
            "hhh.iii.jjj.kkk"
        };

        list.ForEach(x =>
            {
                TreeNode root = parent;
                TreeNode child = null;

                x.Split(new[] { '.' })
                    .ToList()
                    .ForEach(i =>
                    {
                        child = root.Nodes.ContainsKey(i) ?
                            root.Nodes[i] :
                            root.Nodes.Add(i);

                        child.Name = i;
                        root = child;
                    });
            });
    }

此代码完全按照您已发布的内容执行,但只是更小,IMO读取的内容稍微清晰。

通常我会看到一个Action或Func执行一些逻辑来成为代码气味,特别是如果它被重复使用多次(在这种情况下它应该被提取到它自己的方法中,但是我离题)。

在你的情况下,虽然看起来Action仅在行list.ForEach(x => traverse(test, x));中使用了一次,因此功能可以简单地替换你对Action的调用,如上例所示。 (但是,如果逻辑或LOC的复杂性增加,那么在这个例子中,我很想将功能移到它自己的可维护性方法中。)

这种方法还可以让您轻松满足处理字典的第二个要求,只需稍加修改,例如:

    public void DictFunc()
    {
        TreeNode parent = this.treeView1.Nodes.Add("test");

        Dictionary<String, String> dict = new Dictionary<String, String>()
        {
            { "aaa.bbb.ccc.ddd", "Value1" },
            { "aaa.bbb.ccc.eee", "Value2" },
            { "aaa.bbb.fff.ddd", "Value3" },
            { "aaa.bbb.fff.ggg", "Value4" },
            { "aaa.ggg.fff.hhh", "Value5" },
            { "hhh.iii.jjj.kkk", "Value6" }
        };

        dict.ToList().ForEach(x =>
        {
            // For brevity, same as logic in example above.
            // Plus the small amount (~three LOC) of additional logic
            // required to handle the values.
        });
    }

我已将字典值处理作为练习留给您,但ForEach内的其余逻辑与我的第一个示例中的逻辑相同。