最佳实践-具有模拟含义的两个功能

时间:2018-09-16 19:40:14

标签: c# model-view-controller design-patterns

我想知道这种情况下的最佳实践。 兼具这两个功能

选项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的答案,将删除行的逻辑移到删除行的列表,并始终使用行的列表,但是每次创建单个元素的新列表似乎有点开销时,就会创建。

3 个答案:

答案 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}); 
}