我想知道这种情况下的最佳实践。 兼具这两个功能
选项1 -TableController.cs
void deleteRow(Row myRow) {
// do some control on myRow
if (!(myRow.hasThatValue()) && (myRow.Title.StartsWith("xxx"))
return;
Rows.Remove(myRow);
Events.OnRemoveRow(myRow);
}
void deleteRows(List<Row> myRows) {
foreach (var r in myRows) {
deleteRow(r); // That call each time OnRemoveRow()
}
}
选项2 -TableController.cs
void deleteRow(Row myRow) {
// do some control on myRow
if (!(myRow.hasThatValue()) && (myRow.Title.StartsWith("xxx"))
return;
Rows.Remove(myRow);
Events.OnRemoveRow(myRow);
}
void deleteRows(List<Row> myRows) {
foreach (var r in myRows) {
// do some control on myRow
if (!(r.hasThatValue()) && (r.Title.StartsWith("xxx"))
continue;
Rows.Remove(myRow);
}
Events.OnReloadTable(); // That call only one time OnReloadTable()
}
您能发现差异吗?假设您要删除1000行,并在OnRemoveRow事件中删除了ListView中的一行,而是在OnReloadTable事件中清除并重新加载了ListView中的所有行。
使用选项1可以引发在GUI中完成大量工作的事件的1000倍,而使用选项2则只能调用一次重新装入所有行的事件。
使用基准显然可以使选项2的性能更好。
还有一种替代方法或一种更好的方法,可以像选项2一样重复两次相同的代码,但该解决方案具有良好的性能?
编辑:
@Ulf:在示例中,固定循环返回并带有Continue。
如HimBromBeere所建议,我尝试更好地解释该问题: 我有一些用于删除行的冗余代码,我尝试尽可能地简化
从性能的角度来看,每行触发一个事件是浪费。 我正在寻找一种编写较少代码而不影响性能的方法。 从答案中,我看到了解决该问题的两种有效方法。
个人第一解决方案荣誉归功于:Yair Halberstadt
具有内部方法可以解决代码冗余。 第二种解决方案是Mureinik的答案,将删除行的逻辑移到删除行的列表,并始终使用行的列表,但是每次创建单个元素的新列表似乎有点开销时,就会创建。
答案 0 :(得分:3)
您已经注意到,选项#2的性能会更好,但是它会在两种方法之间重复很多代码,并且会导致代码库难以维护。
我会选择第三个选项,其中deleteRows
包含选项#2的性能更好的逻辑,而deleteRow
重用它:
void deleteRow(Row myRow) {
deleteRows(new List<Row>(){myRow});
}
void deleteRows(List<Row> myRows) {
foreach (var r in myRows) {
// do some control on myRow
if (!(myRow.hasThatValue()) && (myRow.Title.StartsWith("xxx"))
return;
Rows.Remove(myRow);
}
Events.OnReloadTable();
}
答案 1 :(得分:2)
添加包含共享逻辑的第三种方法deleteRowInternal
。
public void deleteRow(Row myRow) {
deleteRowInternal(myRow);
Events.OnRemoveRow(myRow);
}
private void deleteRowInternal(Row myRow) {
// do some control on myRow
if (!(myRow.hasThatValue()) &&
(myRow.Title.StartsWith("xxx"))
return;
Rows.Remove(myRow);
}
public void deleteRows(List<Row> myRows) {
foreach (var r in myRows) {
deleteRowInternal(r);
}
Events.OnReloadTable();
}
答案 2 :(得分:1)
您的第二个选项与第一个选项不一致;假设1st
是正确的(您要删除所有具有那个值且不以rows
开头的"xxx"
):
...
foreach (var r in myRows) {
// do some control on myRow
if (!(myRow.hasThatValue()) && (myRow.Title.StartsWith("xxx"))
return; // <- should be "continue";
Rows.Remove(myRow); // <- should be "r"
}
...
为了避免此类错误,我建议在 Linq
的帮助下进行查询// Let's change List<T> into more generic IEnumerable<T>
void deleteRows(IEnumerable<Row> myRows) {
// Readbility: let's put it clear what we are going to remove
var toRemove = myRows
.Where(row => !row.Title?.StartsWith("xxx"))
.Where(row => row.hasThatValue());
// If you have RemoveRange in Rows collection - remove in one go
// Rows.RemoveRange(toRemove);
// If you don't have RemoveRange method, let's loop
foreach (var r in toRemove)
Rows.Remove(r);
Events.OnReloadTable(); // That call only one time OnReloadTable()
}
// Taken from Mureinik's answer (except the collection class wrapper)
void void deleteRow(Row myRow) {
deleteRows(new Row[] {myRow});
}