Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何运用「;“提取方法”;重构为一段代码_C#_.net_Refactoring_.net 2.0 - Fatal编程技术网

C# 如何运用「;“提取方法”;重构为一段代码

C# 如何运用「;“提取方法”;重构为一段代码,c#,.net,refactoring,.net-2.0,C#,.net,Refactoring,.net 2.0,我们有一个遗留应用程序,它有一个1200行长的方法(线程的run方法)。该方法主要是一个单独的while(true),包含一长串句子 以下C#区域在该方法中出现约50次: #region Cancel pending if (backgroundWorkerPrincipal.CancellationPending) { if (CanCancelThread) { ev.Cancel = true;

我们有一个遗留应用程序,它有一个1200行长的方法(线程的run方法)。该方法主要是一个单独的while(true),包含一长串句子

以下C#区域在该方法中出现约50次:

#region Cancel pending
     if (backgroundWorkerPrincipal.CancellationPending)
    {
        if (CanCancelThread)
        {
            ev.Cancel = true;
            return;
        }
    }
#endregion
我想知道用一种新方法提取这个区域的正确方法(如果可能的话)

正如我所说,该片段(区域)在方法中出现了大约50次。请注意#区域内的返回(将退出while)

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

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

        .
        .
        .

    }

}

我不会说有正确的方法来重构它,只是一些可以工作的时髦方法,包括将它提取到一个方法,该方法返回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;
        }
    }
}
var extractedMethods=new Func[]
{
步骤1,
步骤2,
步骤3,
// ...
};
while(true)
{
foreach(提取方法中的函数fn)
{
状态=fn(状态,ev);
if(backgroundWorkerPrincipal.CancellationPending&&Cancancellthread)
{
ev.Cancel=true;
返回;
}
}
}
“调用一个方法,然后在取消挂起时退出”现在与它要调用的方法列表分开,并且您只需要维护一个取消检查。方法列表预先建立,然后输入到该块中。您可以采取额外的步骤,将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 */),
    // ...
};
var extractedMethods=new Func[]
{
(st,ev)=>RunStep1(st,ev/*,特定于RunStep1*/)的参数,
(st,ev)=>RunStep2(st,ev/*,特定于RunStep2*/)的参数,
(st,ev)=>运行步骤3(st,ev/*,特定于运行步骤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;
        }
    }
}
var extractedMethods=new Func[]
{
步骤1,
步骤2,
步骤3,
// ...
};
while(true)
{
foreach(提取方法中的函数fn)
{
状态=fn(状态,ev);
if(backgroundWorkerPrincipal.CancellationPending&&Cancancellthread)
{
ev.Cancel=true;
返回;
}
}
}
“调用一个方法,然后在取消挂起时退出”现在与它要调用的方法列表分开,并且您只需要维护一个取消检查。方法列表预先建立,然后输入到该块中。您可以采取额外的步骤,将while循环提取到它自己的方法中,然后将委托列表传递给它。另一方面,这可能对你的需求来说太过分了

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

另一种选择是使用具有相对简单签名的lambdas,并利用闭包实现abstrac