我们有一个遗留应用程序,它有一个1200行长的方法(一个线程的run方法)。该方法大多是单个while(true),包含一长串句子。
以下C#区域在方法中存在约50次:
#region Cancel pending
if (backgroundWorkerPrincipal.CancellationPending)
{
if (CanCancelThread)
{
ev.Cancel = true;
return;
}
}
#endregion
我想知道将此区域提取到新方法的正确方法(如果可能)。
正如我所说,该片段(Region)在该方法中出现约50次。请注意#region内的返回(会退出一段时间)。
因此该方法具有以下结构:
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 :(得分: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;
}
}
}
&#34;调用方法,然后在取消等待时退出&#34;现在与它要拨打的方法列表分开,你只需要进行一次取消检查。方法列表预先建立,然后输入该块。你可以采取额外的步骤,将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 */),
// ...
};