前言

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

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. 2019年华南理工校赛(春季赛)--I--炒股(简单思维水题)

    水题,想想就过了 题目如下: 链接:https://ac.nowcoder.com/acm/contest/625/I来源:牛客网 攒机一时爽,一直攒机一直爽. 沉迷攒机的胡老师很快就发现,他每天只能 ...

  2. Elasticsearch System Call Filters Failed to Install

    Elasticsearch starts to run, error occurs: : system call filters failed to install; check the logs a ...

  3. Debian 8下手工安装 Eclipse CDT neon.2

    从 http://www.eclipse.org/downloads/packages/eclipse-ide-cc-developers/neon2 下载 eclipse-cpp-neon-2-li ...

  4. 我的C#跨平台之旅(一):从 Hello World 开始

    创建一个“控制台应用程序”,目标框架为“.NET Framework 4.5”,并移除无关的文件及引用,仅保留对 “system.dll”的引用:其中工程文件中核心内容如下: 使用NuGet添加如下引 ...

  5. beautifulsoup爬取糗事百科

    # _*_ coding:utf-8 _*_ import urllib2 from bs4 import BeautifulSoup user_agent = "Mozilla/5.0 ( ...

  6. 冒泡排序 cpp实现

    #include<bits/stdc++.h> using namespace std; void Bubblesort(int a[],int n){ ;i<n-;i++){ ; ...

  7. vue数据双向绑定

    Vue的双向绑定是通过数据劫持结合发布-订阅者模式实现的,即通过Object.defineProperty监听各个属性的setter,然后通知订阅者属性发生变化,触发相应的回调. 整个过程分为以下几步 ...

  8. HTML 通过js实现div的拖动效果

    最近做项目,碰到一个问题,需要对div实现拖动效果. 在度娘找了很多,要么觉得代码太长,要么就是效果不理想,不过最后还是找到了一个不错的,感谢大神的留贴,方便了我们,就把代码贴下面了: <!DO ...

  9. eclipse maven install 报错 jdk rather than jre?

    解决方案:window => Perference => java => install jre => 选中jre => edit => 选择文件夹为jdk的

  10. mysql兼容emoji表情存取

    emoji介绍 Emoji (絵文字,词义来自日语えもじ,e-moji,moji在日语中的含义是字符)是一套起源于日本的12x12像素表情符号,由栗田穣崇(Shigetaka Kurit)创作,最早在 ...