title: c# recursive generics data structure searching
body: <p>been struggling with this for a couple of days now and still stumped.
  i have a data structure that starts with containers that can hold other containers, and eventually leaf nodes. i'm looking for a way of being to iterate thru elements of a type directly, without pulling them into another collection so i can operate on them in place and then save the resulting structure out. </p>
  
  <p>The code below is a noddy version, and if you set a break point on each findElements function you'll see that it drops out without recursing. this is on mono and ms runtimes, so i'm sure it's me not getting something rather than a bug ;)</p>
  
  <p>also, the function should ideally be</p>
  
  <pre><code>IEnumerable&lt;object&gt; findElements&lt;T&gt;();
  </code></pre>
  
  <p>but i can't get the cast to work on this line then :</p>
  
  <pre><code>if (this is T) yield return this;
  </code></pre>
  
  <p>should ideally be </p>
  
  <pre><code>if (this is T) yield return (T)this;
  </code></pre>
  
  <p>thanks for any suggestions / clarity / light</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Text;
  
  namespace covariantTest {
  class MainClass {
      public static void Main(string[] args) {
          Console.WriteLine("Starting");
          Document root = new Document("rooty");
          root.Children.Add(new File("file 1"));
          root.Children.Add(new File("file 2"));
          Document doc2 = new Document("doc2");
          File file3 = new File("file 3");
          file3.Lines.Add(new Line("line 1 file 3"));
          file3.Lines.Add(new Line("line 2 file 3"));
          doc2.Children.Add(file3);
          File file4 = new File("file 4");
          file4.Lines.Add(new Line("stuff about stuff"));
          file4.Lines.Add(new Line("Babylon n ting"));
          file4.Lines.Add(new Line("last line"));
          doc2.Children.Add(file4);
          root.Children.Add(doc2);
  
          // find the lines
          foreach (object obj in root.findElements&lt;Line&gt;()) {
              Line line = obj as Line;
              Console.WriteLine(line.Contents);
          }
          // done
          Console.WriteLine("Press enter to finish");
          Console.ReadLine();
      }
  }// Main
  
  #region classes
  public class Line : ISearchable {
      private string _contents = string.Empty;
  
      public Line() {}
      public Line(string contents) {
          _contents = contents;
      }
      #region properties
      public string Contents {
          get { return _contents; }
          set { _contents = value; }
      }
      #endregion properties
      public IEnumerable&lt;object&gt; findElements&lt;T&gt;() {
          if (this is T) yield return this;
      }
  }// Line
  
  public class File : Container {
      private List&lt;Line&gt; _lines = new List&lt;Line&gt;();
  
      public File() : base() {}
      public File(string name) : base(name) {}
  
      #region properties
      public List&lt;Line&gt; Lines {
          get { return _lines; }
          set { _lines = value; }
      }
      #endregion properties
      public override IEnumerable&lt;object&gt; findElements&lt;T&gt;() {
          if (this is T) yield return this;
          else base.findElements&lt;T&gt;();
      }
  }// File
  
  public class Document : Container {
  
      public Document() : base() {}
      public Document(string name) : base(name) {}
  
      public override IEnumerable&lt;object&gt; findElements&lt;T&gt;() {
          if (this is T) yield return this;
          else base.findElements&lt;T&gt;();
      }
  
  }// Document
  
  public abstract class Container : ISearchable {
      private string _name = string.Empty;
      private List&lt;Container&gt; _children = new List&lt;Container&gt;();
  
      public Container() {}
      public Container(string name) {
          _name = name;
      }
      #region properties
      public string Name { 
          get { return _name; } 
          set { _name = value; }
      }
      public List&lt;Container&gt; Children { 
          get { return _children; } 
          set { _children = value; }
      }
      #endregion properties
      #region interfaces
      public virtual IEnumerable&lt;object&gt; findElements&lt;T&gt;() {
          if (this is T) yield return this;
          foreach (Container item in _children) {
              item.findElements&lt;T&gt;();
          }
      }
      #endregion interfaces
  }// Container
  #endregion classes
  
  #region interfaces
  public interface ISearchable {
      IEnumerable&lt;object&gt; findElements&lt;T&gt;();
  }
  #endregion interfaces
  }// namespace
  </code></pre>