首页 > 解决方案 > 有没有办法重用具有不同结束参数的循环?

问题描述

请不要被代码墙吓倒!简单地说,我的问题如下 - 我可以以某种方式重用代码并放置我想要的任何参数来代替// DoSomething吗?我不想复制和粘贴相同的代码墙,我想减少重复性并更易于维护。我想知道这个问题,但我没有看到一个简单的解决方案,我找不到一个。

for (int i = 0; i < treeListViewDatabase.SelectedObjects.Count; i++)
            {
                if (treeListViewDatabase.SelectedObjects[i] is NodeValueWithNodes rootNode)
                {
                    for (int m = 0; m < rootNode.ChildTreeViewSets.Count; m++)
                    {
                        if (rootNode.ChildTreeViewSets[m] is NodeValueWithNodes childNodeWithNode)
                        {
                            for (int k = 0; k < childNodeWithNode.ChildTreeViewSets.Count; k++)
                            {
                                if (childNodeWithNode.ChildTreeViewSets[k] is NodeValueWithNodes secondChildNodeWithNode)
                                {
                                    for (int p = 0; p < secondChildNodeWithNode.ChildTreeViewSets.Count; p++)
                                    {
                                        if (secondChildNodeWithNode.ChildTreeViewSets[p] is NodeValueWithDevices thirdChildNodeWithDevices)
                                        {
                                            for (int r = 0; r < thirdChildNodeWithDevices.ChildDeviceSet.Count; r++)
                                            {
                                                if (dataRows.Contains(thirdChildNodeWithDevices.ChildDeviceSet[r]))
                                                {
                                                    dataRows.Remove(thirdChildNodeWithDevices.ChildDeviceSet[r]);
                                                }
                                                // DoSomething() 
                                            }
                                        }
                                    }
                                }
                                if (childNodeWithNode.ChildTreeViewSets[k] is NodeValueWithDevices secondChildNodeWithDevice)
                                {
                                    for (int r = 0; r < secondChildNodeWithDevice.ChildDeviceSet.Count; r++)
                                    {
                                        if (dataRows.Contains(secondChildNodeWithDevice.ChildDeviceSet[r]))
                                        {
                                            dataRows.Remove(secondChildNodeWithDevice.ChildDeviceSet[r]);
                                        }
                                        // DoSomething();
                                    }
                                }
                            }
                        }
                        if (rootNode.ChildTreeViewSets[m] is NodeValueWithDevices childNodeDevices)
                        {
                            for (int n = 0; n < childNodeDevices.ChildDeviceSet.Count; n++)
                            {
                                if (dataRows.Contains(childNodeDevices.ChildDeviceSet[n]))
                                {
                                    dataRows.Remove(childNodeDevices.ChildDeviceSet[n]);
                                }
                                // DoSomething();
                            }
                        }
                    }
                }
                if (treeListViewDatabase.SelectedObjects[i] is NodeValueWithDevices rootNodeWithDevices)
                {
                    for (int n = 0; n < rootNodeWithDevices.ChildDeviceSet.Count; n++)
                    {
                        if (dataRows.Contains(rootNodeWithDevices.ChildDeviceSet[n]))
                        {
                            dataRows.Remove(rootNodeWithDevices.ChildDeviceSet[n]);
                        }
                        // DoSomething();
                    }
                }
            }
            for (int i = 0; i < dataRows.Count; i++)
            {
                // DoSomething();
            }

*编辑*

按照人们的建议,我已经完全改变了代码。代码的箭头状外观被简单的递归所取代。此实现使我的问题不存在,因为我可以遍历dataRows以执行必要的操作。

private void TraverseTreeView(IList selectedObjects, List<DataRow> dataRows)
    {
        if (selectedObjects == null)
        {
            return;
        }
        foreach (var selectedObject in selectedObjects)
        {
            if (selectedObject is NodeValueWithNodes withNodes)
            {
                TraverseTreeView(withNodes.ChildTreeViewSets, dataRows);
            }
            if (selectedObject is NodeValueWithDevices withDevices)
            {
                TraverseTreeView(withDevices.ChildDeviceSet, dataRows);
            }
            if (selectedObject is DataRow dataRow && !dataRows.Contains(dataRow))
            {
                dataRows.Add(dataRow);
            }
        }
        
    }

标签: c#

解决方案


您可以使用委托。它可能看起来像这样:

public void TraverseTree(TreeListView root, Action<T> toDo)
{
   //big set of loops goes in here

   //DoSomething(); is replaced with:
   toDo(rootNodeWithDevices.ChildDeviceSet[n]);
}

然后您可以使用 lambda 表达式调用它,如下所示:

Traverse(treeListViewDatabase, (node) => {
    //code for whatever you want to do goes in here
});

我也倾向于首先像这样重写初始循环集:

var items = treeListViewDatabase.SelectedObjects.
    Where(o => o is NodeValueWithNodes).
    Select(o => o.ChildTreeViewSets).
    Where(o => o is NodeValueWithNodes).
    Select(o => o.ChildTreeViewSets).
    Where(o => o is NodeValueWithNodes).
    Select(o => o.ChildTreeViewSets).
    Where(o => o is NodeValueWithDevices).
    Select(o => o.ChildDeviceSet);

foreach(var item in items)
{
    if (dataRows.Contains(item))
        dataRows.Remove(item);
    //DoSomething();
}

如果我绝对必须添加一个ToList()调用以避免在迭代时修改此序列。

做了这么多之后,我会进一步寻求构建一种递归方法来避免那么多重复。例如,我不确定您拥有哪个第三方 TreeListView 控件,但如果它是标准 TreeView 控件,我可能会这样做:

public IEnumerable<TreeNode> Traverse(TreeView source)
{
    // See Local Functions:
    // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/local-functions
    IEnumerable<TreeNode> innerTraverse(TreeNodeCollection root)
    {
        foreach(var node in root)
        {
            yield return node;
            foreach(var node in innerTraverse(root))
            {
                yield return node;
            }
        }
    }

    return innerTraverse(source.nodes));
}

然后像这样使用它:

var items = Traverse(treeListViewDatabase).
    Where(o => o is NodeValueWithDevices).
    Select(o => o.ChildDeviceSet);
foreach(var item in items)
{
    if (dataRows.Contains(item))
        dataRows.Remove(item);
    //DoSomething();
}

这并不完全等价——我们还没有考虑选定的项目及其子项(我会通过构建一个bool IsParentNodeSelected()方法来做到这一点)——但它肯定开始让我们获得更多功能和可重用的代码。


推荐阅读