使用LINQ递归查找通用List C#

时间:2012-11-05 06:43:04

标签: c# winforms linq recursion

我有一个自定义类的通用列表,它有2个属性。这些属性存储表单和另一个表单之间的关系。该列表被构造为分层列表(父/子)关系。我希望能够做的是根据父表单引用获取所有表单的列表,该表单将被传递给函数。我认为最好的方法是使用递归方法进行LINQ查询。我相信有人可以指出我正确的方向

这是列表中使用的类

class FormStack    {

    #region Declares

    private Form _form;
    private Form _parent;

    #endregion

    #region Constructor

    static FormStack()
    {
    }

    #endregion

    public Form Form
    {
        get { return _form; }
        set { _form = value; }
    }

    public Form Parent
    {
        get { return _parent; }
        set { _parent = value; }
    }

}

所以我希望能够调用一个方法并将一个表单引用传递给该函数,并获取与该父项相关的所有子表单。

这是我遇到的一些代码

// create a lookup list
var list = formStack.ToLookup( p => object.ReferenceEquals( p.Parent, parent ) );

// create a function
Func<IEnumerable<Form>, IEnumerable<Form>> recurse = null;
recurse = qs =>
{
    return
        qs
            .Concat(
                from q in qs
                from q2 in recurse( list[] )
                select q2 );
};

// filter the list
var children = recurse( list[parent] ).ToList();

我有一个winform应用程序,它具有标准的CRUD功能。可以说有一个客户列表,每个客户可以有多个地址,这些地址中的每一个都有多个建筑物,我构建表格的方式是有一个客户列表,从这个列表中你可以打开一个详细的表格特定的客户。此表单包含客户的详细信息以及列表中的所有地址。此列表允许用户现在在列表中选择一个地址并打开包含建筑物列表等的地址详细信息表单....我的问题是我想要关闭此客户的客户详细信息和所有相关表单。我的想法是保持表格之间的关系,但也许我有更好的方法???

2 个答案:

答案 0 :(得分:0)

好的,听起来像你有两个问题。一个是语法错误(recurse(list[])错误),但另一个是你的FormStack实际上不是一个堆栈。它只是两种形式,无法创建递归链。我想你想要这个:

public class FormStack : IEnumerable<Form> // or just implement SelectMany
{    
    public Form Form { get; set; }
    public FormStack Parent { get; set; }  
    //implement IEnumerable<Form> or the SelectMany method
}

然后我认为你可以做到这一点,但这似乎是一件尴尬的事情:

Func<FormStack, IEnumerable<Form>> recurse = qs =>
{
    return from q in qs
           select (new[] { qs.Form }).Concat(recurse(qs.Parent));
};

var list = recurse(formStack).ToList();

如果您坚持使用查询语法,那就是这样。

如果我是你,我会忘记所有这些并实施IEnumerator<Form>为你完成这一切:

public class FormStack : IEnumerable<Form> 
{    
    public Form Form { get; set; }
    public FormStack Parent { get; set; }  
    public IEnumerator IEnumerable:GetEnumerator() 
    { 
        return (IEnumerator)GetEnumerator();
    }
    public IEnumerator<Form> GetEnumerator() 
    { 
        return new FormStackEnumerator(this);
    }
}
public class FormStackEnumerator : IEnumerator<Form>
{
    private FormStack _stack;
    private FormStack _first;
    public Form Current { get { return _stack.Form; } }
    object IEnumerator.Current { get { return Current; } }

    public FormStackEnumerator(FormStack stack)
    {
        _stack = stack;
        _first = stack;
    }
    public bool MoveNext()
    {
        if (_stack.Parent == null)
        {
            return false;
        }
        _stack = _stack.Parent;
        return true;
    }
    public void Reset() { _stack = _first; }
    void IDisposable.Dispose() { }
}

然后您在主代码中需要做的就是:

var list = new List<Form>();
foreach (var node in formStack)
{
    list.Add(node.Form);
}

顺便说一句,我只是查找了Form类(我不是WinForms开发人员),而Forms本身也有一个Parent成员。所以你真的不需要将它们包装在一个节点类型的构造中;他们已经是节点!这使一切变得简单:

var list = new List<Form>();

Action<Control> recurse = target =>
{
    var form = target as Form;
    if (form != null)
    {
        list.Add(form);
        recurse(target.Parent);
    }
}

答案 1 :(得分:0)

这是我编写的内容:

为您的所有表单创建基本表单:

public class MyFormBase : Form
{
    public MyFormBase()
    {
        FormRepository.RegisterForm(this);
    }

    public MyFormBase(MyFormBase parent)
        : this()
    {
        Parent = parent;
    }

    public MyFormBase Parent { get; set; }
}

每个Form只能有一个在constuctor中传递的Parent。

创建存储库(或类似的东西)来存储表单 - &gt;我不想将所有孩子都存储在表单中

//infrastructure - simulated with a static class
public static class FormRepository
{
    private static List<MyFormBase> _allForms = new List<MyFormBase>();

    public static void RegisterForm(MyFormBase form)
    {
        _allForms.Add(form);
    }

    public static void CloseFormAndChildren(MyFormBase form)
    {
        _allForms.Where(x => x.Parent.Equals(form)).ToList().ForEach(x => CloseFormAndChildren(x));
        form.Close();
    }
}

在您要关闭的任何表单(包括子项)上调用CloseFormAndChildren。这可以在结束事件中调用......