title: How to use LINQ to select all descendants of a composite object
body: <p>How can I make <code>ComponentTraversal.GetDescendants()</code> better using LINQ?</p>
  
  <h1>Question</h1>
  
  <pre><code>public static class ComponentTraversal
  {
      public static IEnumerable&lt;Component&gt; GetDescendants(this Composite composite)
      {
          //How can I do this better using LINQ?
          IList&lt;Component&gt; 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&lt;Component&gt; Children { get; set; }
  }
  public class Leaf: Component
  {
      public object Value { get; set; }
  }
  </code></pre>
  
  <h1>Answer</h1>
  
  <p>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:</p>
  
  <pre><code>    public static IEnumerable&lt;T&gt; GetDescendants&lt;T&gt;(this T component, Func&lt;T,bool&gt; isComposite, Func&lt;T,IEnumerable&lt;T&gt;&gt; getCompositeChildren)
      {
          var children = getCompositeChildren(component);
          return children
              .Where(isComposite)
              .SelectMany(x =&gt; x.GetDescendants(isComposite, getCompositeChildren))
              .Concat(children);
      }
  </code></pre>
  
  <p>Thanks Chris! </p>
  
  <h2>Also,</h2>
  
  <p>Please look at LukeH's answer at <a href="http://blogs.msdn.com/b/wesdyer/archive/2007/03/23/all-about-iterators.aspx" rel="noreferrer">http://blogs.msdn.com/b/wesdyer/archive/2007/03/23/all-about-iterators.aspx</a> .  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.</p>