在递归中传递父节点

时间:2016-08-26 09:28:39

标签: c# linq recursion linq-to-xml

有没有办法将对象(或引用)传递给函数,当该对象处于'构造之下时?在递归?我想把我的父节点放在他的孩子身上。

以某种方式打电话:

NavigationTreeNode node = FindNode(Resources.ShellView_TreeNodeBusinessRules);
var tmpList = LoadNodes(xDoc.Descendants("root").Elements("tab"), node);

这是递归:

 private List<NavigationTreeNode> LoadNodes(IEnumerable<XElement> nodes, NavigationTreeNode parentNode)
 {
     return nodes.Select(x => 
         new NavigationTreeNode(x.Attribute("display-name").Value, parentNode)
         { 
            TabName = x.Attribute("tab-name").Value,
            // Here I want to send object that is now under 
            // construction, or maybe reference
            ChildNodes = LoadNodes(x.Elements("tab"), /* ?? */)
         }).ToList();
 }

2 个答案:

答案 0 :(得分:2)

您可以添加{}来指定lambda表达式的范围,然后您可以将新对象保存到变量,设置其属性然后将其返回:

return nodes.Select(x => 
{
    var obj = new NavigationTreeNode(x.Attribute("display-name").Value, parentNode)
    { 
        TabName = x.Attribute("tab-name").Value
    };
    obj.ChildNodes = LoadNodes(x.Elements("tab"), obj);
    return obj;
}).ToList();

答案 1 :(得分:0)

坦率地说,如果重新设计导航类,可以做得更好。对于这种特殊情况,该结构不能很好地使用linq来递归地重建它。虽然linq 可以用于初始化递归结构,但当结构被双重链接时,它不能被有效利用。

通常,在初始化结构时创建要使用的子项列表是错误的。当您提供对内部结构的直接访问时,它会破坏封装。无论如何,你应该提供操纵方法。

例如,对于这样的结构,它会使事情变得更容易:

class NavigationTreeNode
{
    private List<NavigationTreeNode> childNodes = new List<NavigationTreeNode>();
    public NavigationTreeNode(string tabName, string displayName)
    {
        TabName = tabName;
        DisplayName = displayName;
    }
    public NavigationTreeNode Parent { get; private set; }
    public string TabName { get; }
    public string DisplayName { get; }
    public IReadOnlyList<NavigationTreeNode> ChildNodes => childNodes.AsReadOnly();

    public void Add(NavigationTreeNode childNode)
    {
        if (childNode.Parent != null)
            childNode.Parent.Remove(childNode);
        childNodes.Add(childNode);
        childNode.Parent = this;
    }

    private void Remove(NavigationTreeNode childNode)
    {
        childNodes.Remove(childNode);
        childNode.Parent = null;
    }
}

然后加载函数看起来像这样:

private NavigationTreeNode LoadNode(XElement node)
{
    var treeNode = new NavigationTreeNode((string)node.Attribute("tab-name"), (string)node.Attribute("display-name"));
    foreach (var tab in node.Elements("tab"))
        treeNode.Add(LoadNode(tab));
    return treeNode;
}

根据您对设计的偏好程度,您可以完全取消对循环的需求,并使用linq完全编写。我会把它作为一种练习留给你。