当您想要递归枚举一个分层对象,根据某些条件选择一些元素时,有许多技术示例,例如“扁平化”,然后使用 Linq 进行过滤:就像在这里找到的那些:
链接文本 https://stackoverflow.com/questions/141467/recursive-list-flattening
但是,当您枚举 Form 的 Controls 集合或 TreeView 的 Nodes 集合之类的内容时,我无法使用这些类型的技术,因为它们似乎需要一个 IEnumerable 参数(扩展方法)集合:传入 SomeForm.Controls 无法编译。
我发现的最有用的东西是:
链接文本 http://blogs.windowsclient.net/rendle/archive/2008/03/06/recursing-controlcollection.aspx
它确实为您提供了 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”这样的奇特事物。我可能会补充说,这是一次“谦卑”的经历:)