在递归中传递 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 编写它。我会把它留给你作为练习。
当 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 编写它。我会把它留给你作为练习。