【问题标题】:Best practice - Two functions with analog meaning最佳实践 - 两个具有类比意义的函数
【发布时间】:2018-09-16 19:40:14
【问题描述】:

我想知道这种情况下的最佳做法是什么。 取这两个函数

选项 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,您将引发 1000 次在 GUI 中执行大量工作的事件,而不是使用选项 2,您只调用一次重新加载所有行的事件。

使用基准显然是选项 2 执行得更好。

所以问题是:

是否有替代或更好的方法,可以像选项 2 一样重复两次相同的代码,但该解决方案的性能良好?

编辑:

@Ulf:在示例中,使用 continue 循环固定返回。

按照 HimBromBeere 的建议,我尝试更好地解释这个问题: 我有一些用于删除一行的冗余代码,我正在尝试尽可能简化

从性能的角度来看,为每一行触发一个事件是一种浪费。 我正在寻找一种在不影响性能的情况下编写更少代码的方法。 从答案中,我看到了解决该问题的两种有效方法。

个人第一个解决方案归功于:Yair Halberstadt

有内部方法可以解决代码冗余。 第二种解决方案是 Mureinik 的答案,将删除行的逻辑移动到删除行列表并始终使用行列表,但每次创建单个元素的新列表时似乎有点开销。

【问题讨论】:

  • 这完全取决于您的环境和上下文。但是,如果您已经做过 基准测试,为什么不信任它们呢?当你的代码做它应该做的事情时,你到底在问什么?
  • 请注意,您应该在选项 2 中使用 continue 而不是 return,以便其行为类似于选项 1。
  • @HimBromBeere:我想减少冗余代码库

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


【解决方案1】:

正如您所指出的,选项 #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();
}

【讨论】:

  • 我会选择第四个:不要回答这个问题,因为它完全不清楚 OP 想要什么。最佳实践往往是基于意见的,特别是在我们对 OP 环境一无所知的情况下。
  • 很好的解决方案,但我认为每次删除一行时创建一个新列表会导致一些开销。
【解决方案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();
 }

【讨论】:

  • 如果我理解正确,您将需要在 deleteRows 方法中使用 Events.OnReloadTable();...
  • 有内部方法的好解决方案!
【解决方案3】:

您的第二个选项与第一个选项不一致;前提是1st 是正确的(您要删除所有具有该值且不以"xxx" 开头的rows):

   ...
   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}); 
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-12
    • 2010-09-11
    • 1970-01-01
    • 1970-01-01
    • 2011-06-25
    • 2011-03-28
    • 1970-01-01
    相关资源
    最近更新 更多