离开函数的时机

离开函数的三种方式中,抛出异常的时机是无法选择的,它关系到函数能否正常执行或者是严重的安全问题,因此一旦出现问题,必须立即抛出异常。而函数自然退出也没有什么值得讨论的意义。真正能影响代码逻辑的,则是通过return语句进行的强制返回。根据结构化程序设计的要求,函数应该分别只有一个入口和出口——这无疑是否定了在函数结尾处之外的位置使用return的权利。不过在实际开发过程中,单出口的要求并不那么实用。例如下面这个程序:

代码示例7-15:使用多出口模式的典型示例
public static PhotoFormat FromExtension(string extension)
{
    switch (extension.ToLower())
    {
        case ".bmp":
            return PhotoFormat.Bmp;
        case ".gif":
            return PhotoFormat.Gif;
        case ".jpg":
        case ".jpeg":
            return PhotoFormat.Jpeg;
        case ".png":
            return PhotoFormat.Png;
        case ".tif":
        case ".tiff":
            return PhotoFormat.Tiff;
        default:
            return PhotoFormat.Unknown;
    }
}

这个程序完全违背了单出口的设计原则,但它仍然非常直观,逻辑清晰可见。阅读程序时,一眼可以看出这个并列关系,一个分支读完,就知道程序执行完毕,无须再阅读后面的部分。相反,如果将其改为单出口模式,我们还必须再引入一个临时的本地变量:

public static PhotoFormat FromExtension(string extension)
{
    PhotoFormat result = null;
    switch (extension.ToLower())
    {
        case ".bmp":
            result = PhotoFormat.Bmp;
            break;
        case ".gif":
            result = PhotoFormat.Gif;
            break;
        case ".jpg":
        case ".jpeg":
            result = PhotoFormat.Jpeg;
            break;
        case ".png":
            result = PhotoFormat.Png;
            break;
        case ".tif":
        case ".tiff":
            result = PhotoFormat.Tiff;
            break;
        default:
            result = PhotoFormat.Unknown;
            break;
    }
    return result;
}

这不但增添了许多break语句,读者读完case分支之后,不得不再寻找switch之后的语句继续阅读,因为他们并不知道后面还会发生什么。代码的可读性显然不如前者。不过,如果分支本身并不能解决所有问题的话,或者并不是每个分支都可以独立完成任务时,下面的单出口模式则更为严谨:
   1:  //代码示例7 16: 采用单出口模式的典型示例
   2:  public Question AddNew(string typeCode)
   3:  {
   4:      Question newq = null;
   5:   
   6:      switch (typeCode)
   7:      {
   8:          case QuestionTypes.Text:
   9:              newq = new TextQuestion(ownerQuestionnaire);
  10:              break;
  11:   
  12:          case QuestionTypes.RadioChoices:
  13:              newq = new RadioChoicesQuestion(ownerQuestionnaire);
  14:              break;
  15:              
  16:          case QuestionTypes.CheckChoices:
  17:              newq = new CheckChoicesQuestion(ownerQuestionnaire);
  18:              break;
  19:   
  20:          case QuestionTypes.RadioTableChoices:
  21:              newq = new RadioTableChoicesQuestion(ownerQuestionnaire);
  22:              break;
  23:   
  24:          default:
  25:              throw new InvalidCastException("未知的问题类型标识:" + typeCode);
  26:      }
  27:   
  28:      Add(newq);
  29:      return newq;
  30:  }

由于switch中每个分支并不能完成所有任务,它们在给出一个中间结果后,还需要进一步的处理。在这个程序中,处理只是简单地调用Add函数,似乎直接写进case分支也不会增加太多的复杂度。但如果这个处理涉及到更多的操作时,分散在case分支内就会导致代码冗余。应该让switch结构专心产生一个中间结果,然后再让后面的代码继续工作,最后从一个出口离开函数。

原文地址:https://www.cnblogs.com/starlet/p/2417871.html