2016-11-07 27 views
0

我们有一个具有1200行长方法(线程的运行方法)的遗留应用程序。该方法大多是一个while(true)包含长句子的序列。如何将“提取方法”重构应用于一段代码

以下C#区存在于该方法大约50倍:

#region Cancel pending 
    if (backgroundWorkerPrincipal.CancellationPending) 
    { 
     if (CanCancelThread) 
     { 
      ev.Cancel = true; 
      return; 
     } 
    } 
#endregion 

我想知道正确的(如果可能的话)的方式于该区域提取到的新方法。

正如我所说,该片段(区域)在该方法内出现约50次。请注意#区域内的退货(将退出此时段)。

因此该方法具有以下结构:

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs ev) 

    while(true) { 

     ... 

     #region Cancel pending 
      if (backgroundWorkerPrincipal.CancellationPending) 
      { 
       if (CanCancelThread) 
       { 
        ev.Cancel = true; 
        return; 
       } 
      } 
     #endregion 

     ... 

     #region Cancel pending 
      if (backgroundWorkerPrincipal.CancellationPending) 
      { 
       if (CanCancelThread) 
       { 
        ev.Cancel = true; 
        return; 
       } 
      } 
     #endregion 

       ... 

     #region Cancel pending 
      if (backgroundWorkerPrincipal.CancellationPending) 
      { 
       if (CanCancelThread) 
       { 
        ev.Cancel = true; 
        return; 
       } 
      } 
     #endregion 

       ... 

     #region Cancel pending 
      if (backgroundWorkerPrincipal.CancellationPending) 
      { 
       if (CanCancelThread) 
       { 
        ev.Cancel = true; 
        return; 
       } 
      } 
     #endregion 

     ... 

     #region Cancel pending 
      if (backgroundWorkerPrincipal.CancellationPending) 
      { 
       if (CanCancelThread) 
       { 
        ev.Cancel = true; 
        return; 
       } 
      } 
     #endregion 

     . 
     . 
     . 

    } 

} 
+0

如果这实际上是被标记为java吗? – nbrooks

+0

@nbrooks很好的捕获。 –

+0

在.net 4.5中,这个'BackgroundWorker'可以替换为'Task','async'和'await'。试一试。 –

回答

3

我不会说,有重构,只是一些时髦的方式来做到这一点,将工作一个正确方式,包括它解压到无论是否执行控制语句都返回true/false的方法。你仍然需要重复50次,所以没有太多的收获。

我不会推荐重构那块代码。相反,我会建议你重构它周围的代码。重构相邻的一段代码有时可能会揭示以前无法识别的模式。

首先为每个“...”块提取方法。你现在拥有的是一种“调用方法,然后保留,如果取消正在等待”的模式。通过将这些方法转换为委托,它们成为数据元素,您可以在它们上循环。

让我们假设一分钟,提取的方法具有相同的签名。声明委托实例的阵列,在一个循环中执行它们,并检查在每个迭代结束时未决的消除。既然你有一个回报而不是休息,你不需要做任何额外的事情来摆脱内部循环。

var extractedMethods = new Func<State, DoWorkEventArgs, State>[] 
{ 
    DoStep1, 
    DoStep2, 
    DoStep3, 
    // ... 
}; 

while (true) 
{ 
    foreach (Func<State, DoWorKEventArgs, State> fn in extractedMethods) 
    { 
     state = fn(state, ev); 

     if (backgroundWorkerPrincipal.CancellationPending && CanCancelThread) 
     { 
      ev.Cancel = true; 
      return; 
     } 
    } 
} 

“调用的方法,然后想逃如果取消挂起”现在从它会调用方法列表中分离,你只有一个取消检查维护。方法列表在前面建立,然后输入到该块中。你可以采取额外的步骤来提取while循环到自己的方法,然后将代表的列表传递给它。另一方面,这可能会让你的需求变得太过分了。

如果提取的方法具有不同的签名,它不是那么简单,但你确实有一些选择。您可以调整方法以采用相同的参数,并让它们忽略它们不使用的参数。参数太多,虽然和可维护性可以开始摆脱你,特别是如果你需要调整50种不同的方法。如果您预见未来需要更多的参数变化,这可能不是一个好的选择。

另一种选择是使用lambda表达式用相对简单的签名,并利用封闭的抽象掉的差异。

var extractedMethods = new Func<State, DoWorKEventArgs, State>[] 
{ 
    (st, ev) => RunStep1(st, ev /*, parameters specific to RunStep1 */), 
    (st, ev) => RunStep2(st, ev /*, parameters specific to RunStep2 */), 
    (st, ev) => RunStep3(st, ev /*, parameters specific to RunStep3 */), 
    // ... 
};