简体   繁体   English

使用LINQ递归查找通用列表C#

[英]Recursive Lookup of generic List C# using LINQ

I have generic list of a custom class which has 2 properties. 我有一个具有2个属性的自定义类的通用列表。 These properties store the raltionship between on form and another form. 这些属性存储形式和另一形式之间的关系。 The list is structured as a hierachical list (parent / child ) relationship. 该列表被构造为层次列表(父/子)关系。 What I want to be able to do is get a list of all forms based on a parent form reference which will be passed to a function. 我想要做的是基于父表单引用获取所有表单的列表,该列表将传递给函数。 I am thinking the best way to go about this is with a LINQ query using a recursive approach. 我认为最好的方法是使用递归方法的LINQ查询。 I am sure someone can point me in the right direction 我相信有人可以指出我正确的方向

This is the class used in the list 这是列表中使用的类

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; }
    }

}

So I would like to be able to Call a method and pass a form reference to the function and get all the children form related to this parent. 因此,我希望能够调用一个方法并将一个表单引用传递给该函数,并获取与此父级相关的所有子表单。

This is some of the code I have been stumbling with 这是我一直在摸索的一些代码

// 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();

I have a winform application which has standard CRUD functionality. 我有一个具有标准CRUD功能的Winform应用程序。 Lets say there is a list of customers and each customer can have multiple address and each one of these addresses have multiple buildings, the way I have structured the forms is there is a list of customers, from this list you can open a detail form for a particular customer. 可以说有一个客户列表,每个客户可以有多个地址,这些地址中的每个地址都有多个建筑物,我构造表单的方式是有一个客户列表,您可以从此列表中打开详细的表单特定客户。 This form has the details of the customer and all the addresses in a list. 此表单在列表中包含客户的详细信息和所有地址。 This list allows the user to now selected an address in the list and open the address details form which has a list of buildings and so on.... My problem is I want to close the customer detail and all the related forms for this customer. 此列表使用户现在可以在列表中选择一个地址,然后打开包含建筑物列表的地址详细信息表单,等等。...我的问题是我想关闭该客户的客户详细信息和所有相关表单。 My idea was to keep of the relationship between the forms, but maybe I there is a better way??? 我的想法是保持表格之间的关系,但也许我有更好的方法?

Okay, it sounds to me like you have two issues. 好吧,听起来像我有两个问题。 One is a syntax error ( recurse(list[]) is wrong), but the other is that your FormStack isn't really a stack. 一个是语法错误( recurse(list[])错误),另一个是您的FormStack并不是真正的堆栈。 It's just two forms, with no way to create a recursive chain. 它只有两种形式,无法创建递归链。 I think you want this: 我想你想要这个:

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
}

Then I think you can just do this, but it seems like an awkward thing to do: 那么我想你可以做到这一点,但它似乎是一个尴尬的事:

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

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

That's if you're insisting on the query syntax. 那就是如果您坚持使用查询语法。

If I were you, though, I'd forget all that and implement an IEnumerator<Form> to do it all for you: 但是,如果我是你,我会忘记所有这些,并实现一个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() { }
}

Then all you'd need to do in your main code is this: 然后,您需要在主代码中执行的所有操作是:

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

By the way, I just looked up the Form class (I'm not a WinForms developer) and the Forms themselves have a Parent member. 顺便说一下,我只是查找了Form类(我不是WinForms开发人员),并且Forms本身有一个Parent成员。 So you don't really need to wrap them in a node-type construct; 因此,您实际上不需要将它们包装在节点类型的构造中。 they're already nodes! 他们已经是节点了! That makes everything easy: 这使一切变得容易:

var list = new List<Form>();

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

here is what I made up: 这是我组成的:

Create a base Form for all your Forms: 为所有表单创建一个基本表单:

 public class MyFormBase : Form { public MyFormBase() { FormRepository.RegisterForm(this); } public MyFormBase(MyFormBase parent) : this() { Parent = parent; } public MyFormBase Parent { get; set; } } 

Each Form can only have one Parent that is passed in the constuctor. 每个表单只能在构造函数中传递一个父级。

Create a Repository (or something simiar) to store your forms -> I do not want to store all children in the Form itself 创建一个存储库(或类似的东西)来存储您的表单->我不想在表单本身中存储所有子级

//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();
    }
}

Call CloseFormAndChildren on any form you want to close (including the children). 以您要关闭的任何形式(包括子项)调用CloseFormAndChildren。 This could be called in the closing event... 这可以在结束事件中调用...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM