前言

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

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. bzoj3110(整体二分)

    #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #inclu ...

  2. windows下qt的.exe的dll文件怎么配齐

    用qt自带的windeploy工具即可 win键打开开始菜单 找到qt目录下的qt for desktop(mingw)并打开 qtcreater或者vs打开要部署的项目,构建成release模式,运 ...

  3. PopupWindow计算弹出位置

    1.首先自定义PopupWindow    popWindowView= LinearLayout.inflate(context, R.layout.popupWindow,null);    po ...

  4. 本学期Windows编程微型技术博客上线!

    将两篇报告生成超链接模式方便阅读,以下为链接: https://files.cnblogs.com/files/Kitty-/Windows编程微型技术报告一.pdf https://files.cn ...

  5. Jeecg框架简介

    官方地址:http://www.jeecg.org/

  6. UniGui中使用Grid++Report报表控件子报表获取数据的方法

    Grid++Report是为优秀的报表控件,子报表是其重要功能之一,但Grid++Report提供的网页报表示范主要是以页面为主的,UniGui在Delphi中以快速编写web管理软件著称,但由于资料 ...

  7. python 二分查找法

    @source_data:数据集 @binary_num:要查找的数 @mid:中间数的键值 def binary_search(source_data,search_num): #传入数据集计算中间 ...

  8. 手把手教你Chrome浏览器安装Postman(含下载云盘链接)【转载】

    转载自:http://www.ljwit.com/archives/php/278.html 说明: Postman不多介绍,是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件.本文主要 ...

  9. Html/CSS前端如何实现文字边框阴影

    上次我们聊了<Html5前端如何实现文字阴影>,其实在开发中现在对于阴影效果的使用已经越来越广泛了,那么今天我们就来说一说用同样的手法实现边框阴影. 一.边框阴影box-shadow 边框 ...

  10. 老罗最新发布了“子弹短信”这款IM,主打熟人社交能否对标微信?

    1.引言 2018年8月20日,锤子科技在北京召开了夏季新品发布会.除了新手机,发布会上还正式推出了主打语音功能的即时通讯IM聊天工具:子弹短信.这款工具此前今年早些时候在「鸟巢」发布会上初次亮相,在 ...