Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.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#_Refactoring - Fatal编程技术网

C# 具有多个返回点的重构方法

C# 具有多个返回点的重构方法,c#,refactoring,C#,Refactoring,**编辑:下面有几个选项可以使用。请根据您对此事的看法进行投票/评论 我正在清理c#方法并将其功能添加到具有以下基本结构的c#方法中: public void processStuff() { Status returnStatus = Status.Success; try { bool step1succeeded = performStep1(); if (!step1succe

**编辑:下面有几个选项可以使用。请根据您对此事的看法进行投票/评论

我正在清理c#方法并将其功能添加到具有以下基本结构的c#方法中:

    public void processStuff()
    {
        Status returnStatus = Status.Success;
        try
        {
            bool step1succeeded = performStep1();
            if (!step1succeeded)
                return Status.Error;

            bool step2suceeded = performStep2();
            if (!step2suceeded)
                return Status.Warning;

            //.. More steps, some of which could change returnStatus..//

            bool step3succeeded = performStep3();
            if (!step3succeeded)
                return Status.Error;
        }
        catch (Exception ex)
        {
            log(ex);
            returnStatus = Status.Error;
        }
        finally
        {
            //some necessary cleanup
        }

        return returnStatus;
    }
有许多步骤,在大多数情况下,步骤x必须成功才能继续执行步骤x+1。现在,我需要添加一些总是在方法末尾运行的功能,但这取决于返回值。我正在寻找关于如何干净地重构它以获得所需效果的建议。显而易见的选择是将依赖于返回值的功能放在调用代码中,但我无法修改调用者

一种选择:

    public void processStuff()
    {
        Status returnStatus = Status.Success;
        try
        {
            bool step1succeeded = performStep1();
            if (!step1succeeded)
            {
                returnStatus =  Status.Error;
                throw new Exception("Error");
            }

            bool step2succeeded = performStep2();
            if (!step2succeeded)
            {
                returnStatus =  Status.Warning;
                throw new Exception("Warning");
            }

            //.. the rest of the steps ..//
        }
        catch (Exception ex)
        {
            log(ex);
        }
        finally
        {
            //some necessary cleanup
        }
        FinalProcessing(returnStatus);
        return returnStatus;
    }
我觉得这有点难看。相反,我可以直接从performStepX()方法中抛出。但是,这就留下了在processStuff()的catch块中正确设置returnStatus变量的问题。正如您可能已经注意到的,处理步骤失败时返回的值取决于失败的步骤

    public void processStuff()
    {
        Status returnStatus = Status.Success;
        try
        {
            bool step1succeeded = performStep1(); //throws on failure
            bool step2succeeded = performStep2(); //throws on failure

            //.. the rest of the steps ..//
        }
        catch (Exception ex)
        {
            log(ex);
            returnStatus = Status.Error;  //This is wrong if step 2 fails!
        }
        finally
        {
            //some necessary cleanup
        }
        FinalProcessing(returnStatus);
        return returnStatus;
    }

如果您有任何建议,我将不胜感激。

您能让
performStep1
performStep2
抛出不同的异常吗?

您可以将这些步骤重构为一个接口,这样每个步骤都会公开一个Run()方法和一个Status属性,而不是一个方法,并且您可以在循环中运行它们,直到你遇到异常。这样,您就可以保留关于运行了哪个步骤以及每个步骤的状态的完整信息。

获取一个元组类。然后做:

var steps = new List<Tuple<Action, Status>>() {
  Tuple.Create(performStep1, Status.Error),
  Tuple.Create(performStep2, Status.Warning)
};
var status = Status.Success;
foreach (var item in steps) {
  try { item.Item1(); }
  catch (Exception ex) {
    log(ex);
    status = item.Item2;
    break;
  } 
}
// "Finally" code here

您可以在
finally
部分中执行处理
finally
很有趣,因为即使您在
try
块中返回了
finally
块,该块仍将在函数实际返回之前执行。不过,它会记住返回的值,因此您也可以在函数的最后舍弃
return

public void processStuff()
{
    Status returnStatus = Status.Success;
    try
    {
        if (!performStep1())
            return returnStatus = Status.Error;

        if (!performStep2())
            return returnStatus = Status.Warning;

        //.. the rest of the steps ..//
    }
    catch (Exception ex)
    {
        log(ex);
        return returnStatus = Status.Exception;
    }
    finally
    {
        //some necessary cleanup

        FinalProcessing(returnStatus);
    }
}

不要使用异常来控制程序流。就我个人而言,我会让代码保持原样。要在最后添加新功能,您可以执行以下操作:

    public void processStuff()
    {
        Status returnStatus = Status.Success;
        try
        {
            if (!performStep1())
                returnStatus = Status.Error;
            else if (!performStep2())
                returnStatus = Status.Warning;

            //.. More steps, some of which could change returnStatus..//

            else if (!performStep3())
                returnStatus = Status.Error;
        }
        catch (Exception ex)
        {
            log(ex);
            returnStatus = Status.Error;
        }
        finally
        {
            //some necessary cleanup
        }

        // Do your FinalProcessing(returnStatus);

        return returnStatus;
    }

您可以反转您的状态设置。在调用异常引发方法之前设置错误状态。最后,如果没有异常,则将其设置为success

Status status = Status.Error;
try {
  var res1 = performStep1(); 
  status = Status.Warning;
  performStep2(res1);
  status = Status.Whatever
  performStep3();
  status = Status.Success; // no exceptions thrown
} catch (Exception ex) {
  log(ex);
} finally {
 // ...
}
那么嵌套的if呢

能工作和不能工作

如果只留下一个,它将删除每个返回

if(performStep1())
{
  if(performStep2())
  {
      //..........
  }
  else 
    returnStatus = Status.Warning;
}
else
  returnStatus = Status.Error;

由于不知道您的逻辑需求是什么,我将首先创建一个抽象类作为一个基本对象来执行特定步骤并返回执行状态。它应该具有可重写的方法来实现任务执行、成功时的操作和失败时的操作。还要处理将逻辑放入此类中以处理任务成功或失败的逻辑:

abstract class TaskBase
{
    public Status ExecuteTask()
    {
        if(ExecuteTaskInternal())
            return HandleSuccess();
        else
            return HandleFailure();
    }

    // overide this to implement the task execution logic
    private virtual bool ExecuteTaskInternal()
    {
        return true;
    }

    // overide this to implement logic for successful completion
    // and return the appropriate success code
    private virtual Status HandleSuccess()
    {
        return Status.Success;
    }

    // overide this to implement the task execution logic
    // and return the appropriate failure code
    private virtual Status HandleFailure()
    {
        return Status.Error;
    }
}
创建任务类以执行步骤后,按执行顺序将其添加到SortedList中,然后在任务完成时对其进行迭代检查STAU:

public void processStuff()
{
    Status returnStatus 
    SortedList<int, TaskBase> list = new SortedList<int, TaskBase>();
    // code or method call to load task list, sorted in order of execution.
    try
    {
        foreach(KeyValuePair<int, TaskBase> task in list)
        {
            Status returnStatus task.Value.ExecuteTask();
            if(returnStatus != Status.Success)
            {
                break;
            }
        }
    }
    catch (Exception ex)
    {
        log(ex);
        returnStatus = Status.Error;
    }
    finally
    {
        //some necessary cleanup
    }

    return returnStatus;
}
public void processStuff()
{
状态返回状态
SortedList=新的SortedList();
//加载任务列表的代码或方法调用,按执行顺序排序。
尝试
{
foreach(列表中的KeyValuePair任务)
{
Status returnStatus task.Value.ExecuteTask();
if(returnStatus!=Status.Success)
{
打破
}
}
}
捕获(例外情况除外)
{
对数(ex);
returnStatus=Status.Error;
}
最后
{
//一些必要的清理
}
返回状态;
}

我留下了错误处理,因为我不确定您在执行任务时捕获错误或只是查找在特定步骤上引发的异常是否失败。

展开上面的接口方法:

public enum Status { OK, Error, Warning, Fatal }

public interface IProcessStage {
    String Error { get; }
    Status Status { get; }
    bool Run();
}

public class SuccessfulStage : IProcessStage {
    public String Error { get { return null; } }
    public Status Status { get { return Status.OK; } }
    public bool Run() { return performStep1(); }
}

public class WarningStage : IProcessStage {
    public String Error { get { return "Warning"; } }
    public Status Status { get { return Status.Warning; } }
    public bool Run() { return performStep2(); }
}

public class ErrorStage : IProcessStage {
    public String Error { get { return "Error"; } }
    public Status Status { get { return Status.Error; } }
    public bool Run() { return performStep3(); }
}

class Program {
    static Status RunAll(List<IProcessStage> stages) {
        Status stat = Status.OK;
        foreach (IProcessStage stage in stages) {
            if (stage.Run() == false) {
                stat = stage.Status;
                if (stat.Equals(Status.Error)) {
                    break;
                }
            }
        }

        // perform final processing
        return stat;
    }

    static void Main(string[] args) {
        List<IProcessStage> stages = new List<IProcessStage> {
            new SuccessfulStage(),
            new WarningStage(),
            new ErrorStage()
        };

        Status stat = Status.OK;
        try {
            stat = RunAll(stages);
        } catch (Exception e) {
            // log exception
            stat = Status.Fatal;
        } finally {
            // cleanup
        }
    }
}
公共枚举状态{正常、错误、警告、致命}
公共接口IProcessStage{
字符串错误{get;}
状态状态{get;}
bool-Run();
}
公共类成功阶段:IProcessStage{
公共字符串错误{get{return null;}}
公共状态状态{get{return Status.OK;}}
public bool Run(){return performStep1();}
}
公共类警告阶段:IProcessStage{
公共字符串错误{获取{返回“警告”;}
公共状态状态{get{return Status.Warning;}
public bool Run(){return performStep2();}
}
公共类ErrorStage:IPProcessStage{
公共字符串错误{get{return“Error”;}
公共状态状态{get{return Status.Error;}
public bool Run(){return performStep3();}
}
班级计划{
静态状态RunAll(列出阶段){
Status stat=Status.OK;
foreach(IProcessStage-in-stages){
if(stage.Run()==false){
stat=阶段状态;
if(stat.Equals(Status.Error)){
打破
}
}
}
//执行最终处理
返回统计;
}
静态void Main(字符串[]参数){
列表阶段=新列表{
新建SuccessfulStage(),
新警告阶段(),
新的ErrorStage()
};
Status stat=Status.OK;
试一试{
stat=运行所有(阶段);
}捕获(例外e){
//日志异常
stat=Status.Fatal;
}最后{
//清理
}
}
}

我建议将这些步骤重构为单独的类,毕竟,您的类应该只承担一项责任。我想这听起来好像是它的责任应该控制这些步骤的运行。

我确实想到了这一点。其他人对这种方法怎么看?我会抛出有意义的异常。你是说抛出带有自定义类型的异常,命名为自定义类型以明确反映其用途吗?我认为抛出并捕获两种不同类型的异常是个好主意。而且,只看一场比赛是个坏主意
public enum Status { OK, Error, Warning, Fatal }

public interface IProcessStage {
    String Error { get; }
    Status Status { get; }
    bool Run();
}

public class SuccessfulStage : IProcessStage {
    public String Error { get { return null; } }
    public Status Status { get { return Status.OK; } }
    public bool Run() { return performStep1(); }
}

public class WarningStage : IProcessStage {
    public String Error { get { return "Warning"; } }
    public Status Status { get { return Status.Warning; } }
    public bool Run() { return performStep2(); }
}

public class ErrorStage : IProcessStage {
    public String Error { get { return "Error"; } }
    public Status Status { get { return Status.Error; } }
    public bool Run() { return performStep3(); }
}

class Program {
    static Status RunAll(List<IProcessStage> stages) {
        Status stat = Status.OK;
        foreach (IProcessStage stage in stages) {
            if (stage.Run() == false) {
                stat = stage.Status;
                if (stat.Equals(Status.Error)) {
                    break;
                }
            }
        }

        // perform final processing
        return stat;
    }

    static void Main(string[] args) {
        List<IProcessStage> stages = new List<IProcessStage> {
            new SuccessfulStage(),
            new WarningStage(),
            new ErrorStage()
        };

        Status stat = Status.OK;
        try {
            stat = RunAll(stages);
        } catch (Exception e) {
            // log exception
            stat = Status.Fatal;
        } finally {
            // cleanup
        }
    }
}