前言

控制流是语言中最基础的部分,我们不谈具体的细节,只讲讲一些关键和有趣的点。

01

流控制

条件语句:if, else if, else

if语句的使用非常值得细讲,如何是好的使用习惯。有一点非常重要,就是尽可能的避免太多层次的嵌套,这将带来可读性灾难。我自己的原则是,if嵌套一般不超过2层,最多不超过3层。可读性是什么?是指:不只是你自己写的代码你自己能读懂,更重要的是当别人接手你的代码的时候,别人能读懂。

If嵌套导致的可读性灾难在Java程序里非常常见,我看别人的遗留代码就是这个感受。一个原因是Java没有像C#这样的linq工具,以及一些语法糖,导致很多常用的计算也要自己写if语句实现,这些代码再套在业务代码中,if层次就很多了,还有比如字段定义都需要生成getter和setter方法(我的Java功力太浅薄,看到大家写Java代码都是这么写,但却不能理解为什么一定要遵循这个范儿),取数判断都是getXXX(),导致布尔表达式代码看着一长串,代码太长又导致很多Java程序员会把一个if拆开成多个嵌套的if来写。比如这个if层次达到了4层(这还不算多,我见过七八层的都有,但一时找不到更多嵌套的例子):

If嵌套层次多会导致什么问题?就是多执行路径的灾难,一个最简单的if else,如果达到3层嵌套,总的可能执行路径就是2*2*2=8。你的程序要保证这8种执行可能性都被考虑到,这导致的结果往往是程序员放弃遵循严谨的逻辑,只考虑正常的业务逻辑,忽略异常的业务逻辑处理。还有些程序员编程习惯不好,只关注if 不关注else,这种程序员的代码里,大量的if语句没有else,往往就隐藏着很多的逻辑地雷。

对于if else的使用,我的使用习惯是:

  1. 写下if时就要想到else怎么处理,程序员要打造的是一个“执行容器”,控制容器边界是他的基本职责。只完成需求而不关注“容器”边界安全的程序员不是合格的程序员。
  2. 优先处理else,就是先处理异常的逻辑,并return,从而将 if else的写法替换为if return,从而使得if else 嵌套层级-1。一段代码中,先后的多个if语句都使用这种方式,可使嵌套层级持续减少,可能原本需要五六层级的if嵌套,最后只需要一级if语句实现,代码健壮性和可读性大大增强。

  1. 如果某些地方只需要写if不需要else,但业务逻辑比较复杂,不是能很直观的理解时,我会写空else,并在else中加注释,说明为什么else为空。

条件语句:switch

有些人不喜欢使用switch,因为if else也能完成switch的功能,因此懒得去分辨该怎么用switch。我对语言(以及框架)的使用原则不是最简单的够用就好,而是为每种语言特性找到适合它的使用场景,并坚持按最佳的使用方式编写代码。Switch的优点是什么?应用于“值相等”的比较,它格式更清晰,写法更简单,可读性更好。

Switch语法还有一种特殊用法是,多个空case语句以使多个值条件下执行同一段代码:

switch(str)

{

case "0":

case "1":

break;

default:

break;

}

循环语句:for,while,do…while,foreach

用的最多的,应该是foreach了,因为循环一个List是当今编写C#代码中最常用的操作了。当你想使用集合的行号时,foreach就不够用了,要用for语句了。非List的循环则会用while,而do…while我很少用,不是它不好用,而是while用习惯了,往往想不起去用do…while。这其实也是在提醒我们:为语言(和类库)特性找到适合它的可明确表述的使用场景是很重要的,因为只有这个意识植入了你心底里,才能在编程中自如的使用最合适的语言特性和类库工具,而不是“都行”,如果遵循的是“都行”的态度,逐渐的你会偏向只使用一种最简单的特性和工具。

循环还有几个小知识点:

For,foreach中的变量可以使用类型推断var,比如:

foreach(var user in list)

for(var i=0; i< 100; i++)

for循环可初始化多个值,比如:

for (int i = 0, j = 0; i < 100; i++, j = j + 2)

foreach循环集合时,不能更改集合项的值。如果要修改,可以使用for循环代替。但如果要在循环中删除集合的某项,for循环也不行了,这个时候可以将集合进行“变身”,使得循环的“集合”和要处理的“集合”成为两个不同的集合,是个技巧,比如:

跳转语句:goto

C#中我从来没用过goto。可以说c#中使用goto几乎没有什么优点,唯一的一个明显用途,是跳出双层循环(后面有例子),goto使得跳出双层循环非常方便,否则我们得自己使用一个独立变量来控制跳出双层循环。

跳转语句:break

Break用于退出switch,以及退出for,foreach,while,do…while的循环。

跳转语句:continue

Continue用于退出for,foreach,while,do…while的当前迭代。

跳转语句:return

Return用于退出类的方法。

我们对比.Net和Java的语法,发现在goto、break、continue上是有区别的。Java没有goto,而使用了break和continue的功能加强来替代goto的功能。而C#保留了goto,且不提供Java中break和continue中加强的功能。

.Net:

Java:

哪种方式更好呢?我更喜欢.Net的处理方式。.Net从实用主义出发,更直观,但可能有些程序员会过度使用goto。而Java表达了语言开发者对Goto的完美厌恶和彻底禁绝,同时,对continue和break的扩展思路非常精妙(但break label稍稍有点别扭)。

本来还想讲枚举,结果发现流控制也讲了不少,那么枚举到下一篇再讲。

枚举概念很简单,但我觉得有必要讨论的是枚举它简单的语言定义,和它在实际应用时存在的鸿沟,应该如何填平的问题。

觉得文章有意义的话,请动动手指,分享给朋友一起来共同学习进步。

欢迎关注本人微信公众号,更及时的关注最新文章(每周三篇原创文章,以及多篇专题文章):

附文:

C#中的&、&&、|、||的区别

详解C#break ,continue, return

上一篇:解读经典《C#高级编程》第七版 Page32-38.核心C#.Chapter2

解读经典《C#高级编程》第七版 Page38-45.核心C#.Chapter2的更多相关文章

  1. c#高级编程第七版 学习笔记 第一章 .NET体系结构

    第一章      .NET体系结构 本章内容: 编译和运行面向.NET的代码 Microsoft中间语言(Microsoft Intermediate Language,MSIL或简称IL)的优点 值 ...

  2. c#高级编程第七版 学习笔记 第二章 核心c#

    第二章 核心C# 本章内容: 声明变量 变量的初始化和作用域 C#的预定义数据类型 在c#程序中使用条件语句.循环和跳转语句执行流 枚举 名称空间 Main()方法 基本的命令行c#编译器选项 使用S ...

  3. c#高级编程第七版 学习笔记 第三章 对象和类型

    第三章 对象和类型 本章的内容: 类和结构的区别 类成员 按值和按引用传送参数 方法重载 构造函数和静态构造函数 只读字段 部分类 静态类 Object类,其他类型都从该类派生而来 3.1 类和结构 ...

  4. C#高级编程第9版 第二章 核心C# 读后笔记

    System命名空间包含了最常用的.NET类型.对应前面第一章的.NET基类.可以这样理解:.NET类提供了大部分的功能,而C#语言本身是提供了规则. pseudo-code,哈哈,秀逗code.伪代 ...

  5. ASP.NET MVC 4高级编程(第4版)

    <ASP.NET MVC 4高级编程(第4版)> 基本信息 作者: (美)Jon Galloway    Phil Haack    Brad Wilson    K. Scott All ...

  6. 《UNIX环境高级编程(第3版)》

    <UNIX环境高级编程(第3版)> 基本信息 原书名:Advanced Programming in the UNIX Environment (3rd Edition) (Addison ...

  7. 【转】apue《UNIX环境高级编程第三版》第一章答案详解

    原文网址:http://blog.csdn.net/hubbybob1/article/details/40859835 大家好,从这周开始学习apue<UNIX环境高级编程第三版>,在此 ...

  8. Linux - Unix环境高级编程(第三版) 代码编译

    Unix环境高级编程(第三版) 代码编译 本文地址:http://blog.csdn.net/caroline_wendy 时间:2014.10.2 1. 下载代码:http://www.apuebo ...

  9. Unix环境高级编程第三版中实例代码如何在自己的linux上运行的问题

    学习Linux已经有2个月了,最近被期末考试把进度耽误了,前几天把Unix环境高级编程看了两章,感觉对Linux的整体有了一些思路,今天尝试着对第一章涉及到的一个简单的交互式shell编译运行一下,结 ...

  10. C#高级编程笔记之第二章:核心C#

    变量的初始化和作用域 C#的预定义数据类型 流控制 枚举 名称空间 预处理命令 C#编程的推荐规则和约定 变量的初始化和作用域 初始化 C#有两个方法可以一确保变量在使用前进行了初始化: 变量是字段, ...

随机推荐

  1. Java WebService 简单实例使用JDK

    原文地址:http://www.cnblogs.com/jasoncc/archive/2011/12/22/2296052.html     什么是WebServices? 它是一种构建应用程序的普 ...

  2. Paper | Octave Convolution(OctConv)

    目录 1. 尺度空间理论(scale-space theory) 2. OctConv 3. 启发 论文:Drop an Octave: Reducing Spatial Redundancy in ...

  3. PostGIS集群

    postgresql集群:https://bbs.csdn.net/topics/390896906?page=1  https://blog.csdn.net/s465689853/article/ ...

  4. socketserver 实现并发

    基于tcp的套接字,关键就是两个循环,一个链接循环,一个通信循环 socketserver模块中分两大类:server类(解决链接问题)和request类(解决通信问题) server类: reque ...

  5. Centos7 网络报错Job for iptables.service failed because the control process exited with error code.

    今天在进行项目联系的时候,启动在待机的虚拟机,发现虚拟机的网络设置又出现了问题. 我以为像往常一样重启网卡服务就能成功,但是它却报了Job for iptables.service failed be ...

  6. MFC编程汇总

    1.visual2017专业版MFC编程环境搭建及第一个MFC程序的创建 2.通过MFC设计一个简单的计价程序 3.控件——静态空间.编辑框控件.命令按钮.复选框和单选控件 4.控件添加——静态控件. ...

  7. Jupyter-NoteBook-你应该知道的N个小技巧

    智能决策上手系列教程索引 不断更新部分内容来自于翻译整理 多行输出 在Notebook的中开头cell中添加以下代码可以实现多行输出: from IPython.core.interactiveshe ...

  8. php中ob_get_contents、curl_multi_init、curl_init多线程下载远程图片并保存记录

    php中三种方式测试图片下载效率 原文共24张不同图,每张大小在500K以上 使用时注意调整传入数组格式以及需要下载时保存地址的路径格式等 这三种方式无需额外安装扩展,方便快捷易操作[虽然效率看结果没 ...

  9. 判断Array/Object

    Object.prototype.isPrototypeOf()  /  Array.prototype.isPrototypeOf()if(typeof items === "object ...

  10. wxPyhon 的控件(摘抄)

    一.静态文本控件 wx.StaticText(parent, id, label, pos=wx.DefaultPosition,    size=wx.DefaultSize, style=0, n ...