gpt4 book ai didi

c# - 如何使用 LINQ 选择复合对象的所有后代

转载 作者:太空狗 更新时间:2023-10-29 22:14:51 24 4
gpt4 key购买 nike

如何使用 LINQ 使 ComponentTraversal.GetDescendants() 更好?

问题

public static class ComponentTraversal
{
public static IEnumerable<Component> GetDescendants(this Composite composite)
{
//How can I do this better using LINQ?
IList<Component> descendants = new Component[]{};
foreach(var child in composite.Children)
{
descendants.Add(child);
if(child is Composite)
{
descendants.AddRange((child as Composite).GetDescendants());
}
}
return descendants;
}
}
public class Component
{
public string Name { get; set; }
}
public class Composite: Component
{
public IEnumerable<Component> Children { get; set; }
}
public class Leaf: Component
{
public object Value { get; set; }
}

回答

我编辑了 Chris 的回答以提供一个我已添加到我的公共(public)库中的通用扩展方法。我可以看到这对其他人也有帮助,所以这里是:

    public static IEnumerable<T> GetDescendants<T>(this T component, Func<T,bool> isComposite, Func<T,IEnumerable<T>> getCompositeChildren)
{
var children = getCompositeChildren(component);
return children
.Where(isComposite)
.SelectMany(x => x.GetDescendants(isComposite, getCompositeChildren))
.Concat(children);
}

谢谢克里斯!

另外,

请查看 LukeH 的回答 http://blogs.msdn.com/b/wesdyer/archive/2007/03/23/all-about-iterators.aspx .他的回答提供了一个更好的方法来解决这个问题,但我没有选择它,因为它不是我问题的直接答案。

最佳答案

通常有充分的理由避免(1) 递归方法调用、(2) 嵌套迭代器和(3) 大量一次性分配。这种方法避免了所有这些潜在的陷阱:

public static IEnumerable<Component> GetDescendants(this Composite composite)
{
var stack = new Stack<Component>();
do
{
if (composite != null)
{
// this will currently yield the children in reverse order
// use "composite.Children.Reverse()" to maintain original order
foreach (var child in composite.Children)
{
stack.Push(child);
}
}

if (stack.Count == 0)
break;

Component component = stack.Pop();
yield return component;

composite = component as Composite;
} while (true);
}

这是通用的等价物:

public static IEnumerable<T> GetDescendants<T>(this T component,
Func<T, bool> hasChildren, Func<T, IEnumerable<T>> getChildren)
{
var stack = new Stack<T>();
do
{
if (hasChildren(component))
{
// this will currently yield the children in reverse order
// use "composite.Children.Reverse()" to maintain original order
// or let the "getChildren" delegate handle the ordering
foreach (var child in getChildren(component))
{
stack.Push(child);
}
}

if (stack.Count == 0)
break;

component = stack.Pop();
yield return component;
} while (true);
}

关于c# - 如何使用 LINQ 选择复合对象的所有后代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5262201/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com