c#递归泛型数据结构搜索

c#递归泛型数据结构搜索,c#,generics,recursion,C#,Generics,Recursion,我已经为此挣扎了好几天了,但仍然感到困惑。 我有一个数据结构,它从可以容纳其他容器的容器开始,最后是叶节点。我正在寻找一种直接迭代类型元素的方法,而不将它们拉入另一个集合,这样我就可以在适当的位置对它们进行操作,然后保存生成的结构 下面的代码是一个noddy版本,如果您在每个findElements函数上设置一个断点,您将看到它在不递归的情况下退出。这是在mono和ms运行时上进行的,所以我肯定是我没有得到什么东西,而不是一个bug;) 此外,理想情况下,函数应为 IEnumerable<

我已经为此挣扎了好几天了,但仍然感到困惑。 我有一个数据结构,它从可以容纳其他容器的容器开始,最后是叶节点。我正在寻找一种直接迭代类型元素的方法,而不将它们拉入另一个集合,这样我就可以在适当的位置对它们进行操作,然后保存生成的结构

下面的代码是一个noddy版本,如果您在每个findElements函数上设置一个断点,您将看到它在不递归的情况下退出。这是在mono和ms运行时上进行的,所以我肯定是我没有得到什么东西,而不是一个bug;)

此外,理想情况下,函数应为

IEnumerable<object> findElements<T>();
最好是

if (this is T) yield return (T)this;
谢谢你的建议/清晰/轻松

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<Line>()) {
            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<object> findElements<T>() {
        if (this is T) yield return this;
    }
}// Line

public class File : Container {
    private List<Line> _lines = new List<Line>();

    public File() : base() {}
    public File(string name) : base(name) {}

    #region properties
    public List<Line> Lines {
        get { return _lines; }
        set { _lines = value; }
    }
    #endregion properties
    public override IEnumerable<object> findElements<T>() {
        if (this is T) yield return this;
        else base.findElements<T>();
    }
}// File

public class Document : Container {

    public Document() : base() {}
    public Document(string name) : base(name) {}

    public override IEnumerable<object> findElements<T>() {
        if (this is T) yield return this;
        else base.findElements<T>();
    }

}// Document

public abstract class Container : ISearchable {
    private string _name = string.Empty;
    private List<Container> _children = new List<Container>();

    public Container() {}
    public Container(string name) {
        _name = name;
    }
    #region properties
    public string Name { 
        get { return _name; } 
        set { _name = value; }
    }
    public List<Container> Children { 
        get { return _children; } 
        set { _children = value; }
    }
    #endregion properties
    #region interfaces
    public virtual IEnumerable<object> findElements<T>() {
        if (this is T) yield return this;
        foreach (Container item in _children) {
            item.findElements<T>();
        }
    }
    #endregion interfaces
}// Container
#endregion classes

#region interfaces
public interface ISearchable {
    IEnumerable<object> findElements<T>();
}
#endregion interfaces
}// namespace
使用系统;
使用System.Collections.Generic;
使用系统文本;
命名空间协变项{
类主类{
公共静态void Main(字符串[]args){
控制台写入线(“启动”);
文档根=新文档(“根”);
添加(新文件(“文件1”);
添加(新文件(“文件2”);
文件doc2=新文件(“doc2”);
文件file3=新文件(“文件3”);
file3.Lines.Add(新行(“第1行文件3”);
添加(新行(“第2行文件3”);
doc2.Children.Add(文件3);
文件file4=新文件(“文件4”);
file4.Lines.Add(新行(“stuff about stuff”);
文件4.行。添加(新行(“巴比伦n庭”);
file4.Lines.Add(新行(“最后一行”);
doc2.Children.Add(文件4);
root.Children.Add(doc2);
//找出台词
foreach(root.findElements()中的对象obj){
直线=obj作为直线;
Console.WriteLine(行内容);
}
//完成
Console.WriteLine(“按enter键完成”);
Console.ReadLine();
}
}//主要
#区域类
公共类行:ISearchable{
私有字符串_contents=string.Empty;
公用线路(){}
公用行(字符串内容){
_内容=内容;
}
#区域属性
公共字符串内容{
获取{return\u contents;}
设置{u contents=value;}
}
#端域属性
公共IEnumerable findElements(){
如果(这是T)收益率,则返回该收益率;
}
}//线
公共类文件:容器{
私有列表_行=新列表();
公共文件():基(){}
公共文件(字符串名称):基(名称){}
#区域属性
公共列表行{
获取{返回_行;}
设置{u行=值;}
}
#端域属性
公共覆盖IEnumerable findElements(){
如果(这是T)收益率,则返回该收益率;
else base.findElements();
}
}//文件
公共类文档:容器{
公共文档():基(){}
公共文档(字符串名称):基(名称){}
公共覆盖IEnumerable findElements(){
如果(这是T)收益率,则返回该收益率;
else base.findElements();
}
}//文件
公共抽象类容器:ISearchable{
私有字符串_name=string.Empty;
私有列表_children=新列表();
公共容器(){}
公共容器(字符串名称){
_名称=名称;
}
#区域属性
公共字符串名称{
获取{return\u name;}
设置{u name=value;}
}
公开儿童名单{
获取{return\u children;}
设置{u children=value;}
}
#端域属性
#区域界面
公共虚拟IEnumerable findElements(){
如果(这是T)收益率,则返回该收益率;
foreach(子容器中的容器项目){
item.findElements();
}
}
#端域接口
}//容器
#端域类
#区域界面
公共接口是可实现的{
IEnumerable findElements();
}
#端域接口
}//名称空间

我认为您的代码有点复杂,但我可能不太理解您的目标。
不管怎样,这里有一个样本,可以用“平面方式”扫描你的树。我还使用了一个非常小的代码来演示如何操作,但显然您必须继续操作。

namespace ConsoleApplication3
{
    //this is a node of your tree, but you may add whatever you want inside
    class Item
    {
        public List<Item> Items { get; set; }
    }


    class Program
    {
        static void Main(string[] args)
        {
            //define the tree structure
            var tree = new Item();

            // (complete your tree-structrure)

            //define the action delegate
            Action<Item> action = (item) => Console.WriteLine(item);

            //scan the hierarchy
            Scan(
                tree,
                typeof(Item),
                action);
        }


        //here is the flat-scan function, the "typeToFind" here is just
        //for example and have very little sense to be in
        static void Scan(
            Item startItem,
            Type typeToFind,
            Action<Item> action)
        {
            var temp = new List<Item>();
            temp.Add(startItem);

            while (temp.Count > 0)
            {
                var item = temp[0];
                temp.RemoveAt(0);

                if (typeToFind.IsInstanceOfType(item))
                {
                    action(item);
                }

                temp.AddRange(item.Items);
            }
        }
    }
}
命名空间控制台应用程序3
{
//这是树的一个节点,但您可以在其中添加任何需要的内容
类项目
{
公共列表项{get;set;}
}
班级计划
{
静态void Main(字符串[]参数)
{
//定义树结构
变量树=新项();
//(完成您的树结构)
//定义动作委托
动作动作=(项目)=>Console.WriteLine(项目);
//扫描层次结构
扫描(
树,
(项目)的类型,
行动);
}
//这是平面扫描功能,这里的“typeToFind”只是
//比如说,你没有什么意义
静态空洞扫描(
startItem项目,
键入typeToFind,
行动(行动)
{
var temp=新列表();
添加温度(startItem);
而(温度计数>0)
{
var项目=温度[0];
移除温度(0);
if(类型查找IsInstanceOfType(项目))
{
行动(项目);
}
临时添加范围(项目);
}
}
}
}

希望这有帮助。干杯。

您希望它如何工作?如果我理解正确,那么当从另一个函数调用yield时,yield不起作用(因此,如果调用base.findElements,则不会从中得到任何结果)。我建议不让步地重写它。为了避免创建许多列表,我将以如下方式将列表作为参数传递:

public interface ISearchable {
    void doFindElements<T>(List<T> putThemHere);
}

// this is extender for syntactical sugar
public static class SearchableExtender
{
    public static IEnumerable<T> findElements<T>(this ISearchable obj)
    {
        List<T> result = new List<T>();
        obj.doFindElements(result);
        return result;
    }
}

public abstract class Container : ISearchable {
...
    public virtual void doFindElements<T>(List<T> putThemHere)
    {
        if (this is T) putThemHere.Add(this);
        foreach (Container item in _children) { item.doFindElements(putThemHere); }
    }
...
}
公共接口是可实现的{
作废doFindElements(在此处列出);
}
//这是合成糖的延长剂
公共静态类SearchableExtender
{
公共静态IEnumerable findElements(此ISearchable obj)
public interface ISearchable {
    void doFindElements<T>(List<T> putThemHere);
}

// this is extender for syntactical sugar
public static class SearchableExtender
{
    public static IEnumerable<T> findElements<T>(this ISearchable obj)
    {
        List<T> result = new List<T>();
        obj.doFindElements(result);
        return result;
    }
}

public abstract class Container : ISearchable {
...
    public virtual void doFindElements<T>(List<T> putThemHere)
    {
        if (this is T) putThemHere.Add(this);
        foreach (Container item in _children) { item.doFindElements(putThemHere); }
    }
...
}