有没有一种方法可以重用具有不同结束参数的循环



请不要被代码墙吓倒!简单地说,我的问题是:我是否可以以某种方式重用代码,并将我想要的任何参数放在//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);
}
}

}

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

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://learn.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()方法来实现(——但它肯定开始让我们获得更多功能性和可重复使用的代码。

考虑使用递归函数(一个调用自身的函数(。例如,遍历Treeview并返回所有节点及其子节点和子节点的列表,等等。:

private List<TreeNode> GetAllNodes(TreeNodeCollection nodes)
{
List<TreeNode> retNodes = new List<TreeNode>();
foreach (TreeNode node in nodes)
{
retNodes.Add(node);
retNodes.AddRange(GetAllNodes(node.Nodes));
}
return retNodes;
}

最新更新