在递归中传递 parent 节点

Passing parent node in recursion

当 object 在 'construction' 递归下时,有什么方法可以将 object(或引用)传递给函数吗?我想在他的 child.

中保留我的 parent 节点

某个方法中的调用位置:

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();
 }

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

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();

坦率地说,如果您重新设计导航 类,这可以做得更好。对于这种特殊情况,该结构不适合使用 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 编写它。我会把它留给你作为练习。