如何使用LINQ来选择一个组合对象的所有后代 [英] How to use LINQ to select all descendants of a composite object

查看:256
本文介绍了如何使用LINQ来选择一个组合对象的所有后代的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何才能让 ComponentTraversal.GetDescendants()更好地使用LINQ?

问题

 公共静态类ComponentTraversal
{
    公共静态的IEnumerable<成分> GetDescendants(该复合复合)
    {
        //我能如何使用LINQ这更好的?
        IList的<成分>后人=新的组件[] {};
        的foreach(VAR孩子在composite.Children)
        {
            descendants.Add(子);
            如果(孩子综合)
            {
                descendants.AddRange((子复合).GetDescendants());
            }
        }
        返回的后裔;
    }
}
公共类组件
{
    公共字符串名称{;组; }
}
公共类复合:组件
{
    公开的IEnumerable<成分>儿童{获得;组; }
}
公共类叶:组件
{
    公共对象值{获得;组; }
}
 

答案

我编辑克里斯的回答来提供,我已经加入到我的公共库的通用扩展方法。我可以看到这是其他人也因此在这里有帮助的是:

 公共静态的IEnumerable< T> GetDescendants< T>(这件T组件,Func键< T,布尔> isComposite,Func键< T,IEnumerable的< T>> getCompositeChildren)
    {
        VAR孩子= getCompositeChildren(组件);
        返回儿童
            。凡(isComposite)
            .SelectMany(X => x.GetDescendants(isComposite,getCompositeChildren))
            .Concat(儿童);
    }
 

感谢克里斯!

另外,

请看看LukeH的回答在<一个href="http://blogs.msdn.com/b/wesdyer/archive/2007/03/23/all-about-iterators.aspx">http://blogs.msdn.com/b/wesdyer/archive/2007/03/23/all-about-iterators.aspx 。他的回答提供了一个更好的方式来处理,一般这个问题,但我没有选择它,因为它不是直接回答我的问题。

解决方案

  VAR的结果= composite.Children.OfType&lt;复合&GT;()的SelectMany(子=&GT;。child.GetDescendants( ))CONCAT(composite.Children)。
返回result.ToList();
 

在做从imperitive语法LINQ翻译,它通常是pretty的易取的翻译一步一个脚印的时间。下面是如何工作的:

  1. 这是遍历composite.Children,所以这将是集合我们应用的LINQ to。
  2. 一般有两种操作存在的在循环,所以让我们做他们的一次
  3. 在如果语句进行过滤。通常情况下,我们将使用位置,以执行一个过滤器,但在这种情况下,滤波器是基于类型。 LINQ有OfType建在此。
  4. 对于每一个孩子的复合,我们要递归调用GetDescendants并将结果添加到一个列表。每当我们想改造一个元素成别的东西,我们采用两种选择或的SelectMany。既然我们要转换的每个元素到一个列表,并把它们合并在一起,我们使用的SelectMany。
  5. 最后,在composite.Children自己添加,我们串连这些结果到最后。

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.

解决方案

var result = composite.Children.OfType<Composite>().SelectMany(child => child.GetDescendants()).Concat(composite.Children);
return result.ToList();

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:

  1. This is looping over composite.Children, so that will be the collection we apply LINQ to.
  2. There are two general operations occuring in the loop, so lets do one of them at a time
  3. The "if" statement is performing a filter. Normally, we would use "Where" to perform a filter, but in this case the filter is based on type. LINQ has "OfType" built in for this.
  4. For each child composite, we want to recursively call GetDescendants and add the results to a single list. Whenever we want to transform an element into something else, we use either Select or SelectMany. Since we want to transform each element into a list and merge them all together, we use SelectMany.
  5. Finally, to add in the composite.Children themselves, we concatenate those results to the end.

这篇关于如何使用LINQ来选择一个组合对象的所有后代的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆