如何使用 LINQ 选择复合对象的所有后代
如何使用 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; }
}
解答
我编辑了克里斯的答案,以提供我已添加到我的公共库中的通用扩展方法。我可以看到这对其他人也有帮助,所以这里是:
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。他的回答提供了一种更好的方法来解决这个问题,但我没有选择它,因为它不是我的问题的直接答案。
How can I make ComponentTraversal.GetDescendants()
better using LINQ?
Question
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; }
}
Answer
I edited Chris's answer to provide a generic extension method that I've added to my Common library. I can see this being helpful for other people as well so here it is:
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);
}
Thanks Chris!
Also,
Please look at LukeH's answer at http://blogs.msdn.com/b/wesdyer/archive/2007/03/23/all-about-iterators.aspx . His answer provides a better way to approach this problem in general, but I did not select it because it was not a direct answer to my question.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我不知道更好,但我认为这执行相同的逻辑:
它可能更短,但你所拥有的没有任何问题。正如我上面所说,这应该执行相同的事情,我怀疑该函数的性能是否得到了提高。
I don't know about better, but I think this performs the same logic:
It might be shorter, but there is nothing wrong with what you have. As I said above, this is supposed to perform the same thing and I doubt that the performance of the function is improved.
当您可能想要实现迭代器时,这是一个很好的示例。这具有以稍微更具可读性的语法进行惰性求值的优点。另外,如果您需要添加额外的自定义逻辑,那么此表单更具可扩展性
This is a good example for when you might want to implement an iterator. This has the advantage of lazy evaluation in a slightly more readable syntax. Also, if you need to add additional custom logic then this form is more extensible
通常有充分的理由避免(1)递归方法调用、(2)嵌套迭代器和(3)大量一次性分配。这种方法避免了所有这些潜在的陷阱:
这是通用的等效方法:
There are often good reasons to avoid (1) recursive method calls, (2) nested iterators, and (3) lots of throwaway allocations. This method avoids all of those potential pitfalls:
And here's the generic equivalent:
当从命令式语法转换为 LINQ 时,一次一步地进行转换通常非常容易。这是它的工作原理:
When doing a translation from imperitive syntax to LINQ, it is usually pretty easy to take the translation one step at a time. Here is how this works: