编码模式c#

时间:2012-10-27 17:24:10

标签: c# refactoring

前几天我在代码审查中遇到了一些看起来像这样的代码。

public void DoSomeTasks()
{
  if (CheckSomeState()==true) return;
    DoTaskOne();
  if (CheckSomeState()==true) return;
    DoTaskTwo();
  if (CheckSomeState()==true) return;
    DoTaskThree();
  if (CheckSomeState()==true) return;
    DoTaskFour(); 
}

随着任务数量的增加,代码最终会出现更高的圈复杂度,而且对我来说也感觉不对。

我提出解决此问题的解决方案是。

private void DoTasksWhile(Func<bool> condition, Action[] tasks)
{
   foreach (var task in tasks)
   {
      if (condition.Invoke()==false) break;
        task.Invoke();
   }
}

像这样使用

public void DoSomeTasks()
{
 var tasks = new Action[] { 
  {()=DoTaskOne()},
  {()=DoTaskTwo()},
  {()=DoTaskThree()},
  {()=DoTaskFour()}

  }

  DoTasksWhile(()=>CheckSomeState(), tasks);
}

任何人都有任何建议让代码更具可读性吗?

3 个答案:

答案 0 :(得分:4)

我对您的实现进行了一些重构

private void DoTasksWhile(Func<bool> predicate, IEnumerable<Action> tasks)
{
    foreach (var task in tasks)
    {
        if (!predicate())
            return;
        task();
    }
}
  • 您不需要Invoke名代表。只需执行它们
  • 不要将布尔值与true/false进行比较(它没用,你可以错误地指定布尔值)
  • 因此您只需枚举任务,IEnumerable适用于参数

您也可以创建扩展方法

public static void DoWhile(this IEnumerable<Action> actions,Func<bool> predicate)
{
    foreach (var action in actions)
    {
        if (!predicate())
            return;
        actions();
    }
}

用法非常简单:

tasks.DoWhile(() => CheckSomeState());

答案 1 :(得分:1)

如果您的业务流程代码非常复杂,请考虑使用WF(工作流基础)等框架。

否则,您的代码很好,但我不会更改初始代码,因为它更具可读性。它也更灵活,因为将来您可以修改这些IF,即条件可能不会保持相同。

我没有看到圈降复杂性如何降低或降低。

答案 2 :(得分:0)

你的解决方案是完全足够的(尽管在四个步骤的情况下可能有点过分),但在这种情况下它是否是最好的方法取决于CheckSomeState在你的程序环境中的实际目的是什么:

  • 在每个任务之间只调用一次CheckSomeState是否重要?
  • 有时候还需要在任务中途调用吗?

因此,例如,如果CheckSomeState实际上正在检查取消标志,那么在长时间运行的任务中可能需要额外的检查。

您可以使用的另一个选项是抛出异常(例如OperationCancelledException)。这可以使您的圈复杂度非常低,您现在可以做到:

CheckForCancel();
DoTaskOne();
CheckForCancel();
DoTaskTwo();

(缺点是有些人会认为这是使用控制流的异常,这通常是不赞成的。)

我还应该补充一点,目标不应该是减少圈复杂度,而是要使代码易于理解和维护。循环复杂性是一个有用的指标,但它有时会不必要地惩罚代码非常简单。