c# - 有没有办法重用具有不同结束参数的循环?
问题描述
请不要被代码墙吓倒!简单地说,我的问题如下 - 我可以以某种方式重用代码并放置我想要的任何参数来代替// 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://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()
方法来做到这一点)——但它肯定开始让我们获得更多功能和可重用的代码。
推荐阅读
- python - 获得最大数量的产品给予金钱限制
- java - 在 Apache Ignite 中释放锁定时出现 IllegalMonitorStateException
- flutter - 尝试为 iOS 运行或构建 Flutter 项目时出错
- python - 索引错误:索引 2 超出轴 0 的范围,大小为 2
- java - 使用 Maven 和 logback 配置 Apache Spark 日志记录,最后向 Loggly 抛出消息
- android - 无法在 Firebase 中看到事件
- sql - Oracle SQL - 选择大数字作为十六进制字符串
- javascript - 是否可以使用 getDisplayMedia() 禁用光标记录
- android - - 如何解决:ParentDataWidget 使用不正确?
- javascript - 如何链接 api 调用,并循环直到对象等于特定值