当您想要递归枚举分层对象,根据某些标准选择一些元素时,有许多技术示例,例如“展平”,然后使用 Linq 进行过滤:就像在此处找到的那样:
但是,当您枚举诸如 Form 的 Controls 集合或 TreeView 的 Nodes 集合之类的东西时,我无法使用这些类型的技术,因为它们似乎需要一个 IEnumerable 参数(扩展方法) collection : 传入 SomeForm.Controls 不会编译。
我发现最有用的是:
这确实为您提供了 Control.ControlCollection 的扩展方法,其结果为 IEnumerable,然后您可以将其与 Linq 一起使用。
我已经修改了上面的示例以毫无问题地解析 TreeView 的节点。
public static IEnumerable<TreeNode> GetNodesRecursively(this TreeNodeCollection nodeCollection)
{
foreach (TreeNode theNode in nodeCollection)
{
yield return theNode;
if (theNode.Nodes.Count > 0)
{
foreach (TreeNode subNode in theNode.Nodes.GetNodesRecursively())
{
yield return subNode;
}
}
}
}
这是我现在使用扩展方法编写的那种代码:
var theNodes = treeView1.Nodes.GetNodesRecursively();
var filteredNodes =
(
from n in theNodes
where n.Text.Contains("1")
select n
).ToList();
而且我认为在传入约束的情况下,可能有一种更优雅的方式来做到这一点。
我想知道是否可以通用地定义这样的过程,以便:在运行时我可以将集合的类型以及实际集合传递给通用参数,因此代码与是否它是 TreeNodeCollection 或 Controls.Collection。
我也很想知道是否有任何其他方式(更便宜?更快?)而不是第二个链接(上面)中显示的方式来获取 Linq 可用的形式的 TreeNodeCollection 或 Control.ControlCollection。
Leppie 在链接到第一个(上图)的 SO 帖子中关于“SelectMany”的评论似乎是一个线索。
我对 SelectMany 的实验是:好吧,称它们为“灾难”。:)
感谢任何指针。我花了几个小时阅读我能找到的所有涉及这些领域的 SO 帖子,并漫无目的地进入“y-combinator”这样的异国情调。一个“谦卑”的经历,我可能会补充:)