第 15 讲:程序结构(一):条件结构
我们前面用了六个文章介绍了运算符的使用。今天我们进入新的板块:程序控制结构。C 语言里,程序控制结构一共有四种:顺序结构、条件结构、循环结构和跳转结构。C# 里一共是 5 种:顺序结构、条件结构、循环结构、跳转结构和异常控制结构。顺序结构是最基础的结构,在前面的文章早就体现过了,只是没有提出它的名称。只要一段代码从上到下依次执行的过程,我们就把这段代码称为顺序结构。
Part 1 if
的用法
1-1 if
语句
前面的内容我们无法控制代码在指定条件的时候,才做一些工作。当我们需要这样的用法的话,我们将使用 if
语句来控制。
格式是这样的:
有这样两种写法。我们来写一个例子。
在这个例子里,我们在 if (a > b)
之后使用大括号,将 Console.WriteLine
完整包裹起来。这表示,用大括号包裹起来的所有内容,都属于“当 a > b
成立的时候,才会执行的逻辑”。
当 a > b
的结果是 false
(即不成立)的时候,不管大括号里有多少东西,都不会得到执行,会被完全忽视掉。显然,这个例子里,30 是比 40 小的,所以条件并不成立。因此,你在执行过程之中,什么输出都看不到。
顺带一说,既然用到了大括号,那么里面的内容就需要缩进来保证代码的整洁。如果大括号内的内容不缩进的话,看起来就很奇怪。当然,它并不影响编译程序和运行程序就是了。
1-2 else
语句
显然,这样的格式并不能满足我们正常的需求。前文的例子我们其实还想看到另外一个输出内容,“b
比 a
大”,但在代码里没有体现。因此,else
就派上用场了。
和 if
差不多,else
后也是跟一个大括号,或者一个单独的语句。这部分表示在 if
条件并不成立的时候,才会得到执行。
如果我们这么写代码的话,这就表示,当 if (a > b)
里的 a > b
条件成立的时候,会输出 a
比 b
大的内容;但是如果不成立,就会输出 b
大于 a
的内容。
if
-else
整体的话,if
的部分和 else
的部分并不会都执行,也必然必须执行至少一个部分。这就是 if
-else
配合一起使用的时候的特点。
当然,前文说过,空格是不影响编译和运行程序的,因此我们甚至可以写在一行:
这么写依然是没有问题的。代码写成什么样看的是个人的习惯,只要逻辑没有问题就行。
1-3 else
后也不一定非得是大括号和语句
a > b
的对立情况就一定是 b > a
吗?当然不是,还可以相等。但是我们刚才没有体现这一点。下面我们来试着添加这个部分:
当 a > b
条件不成立的时候,我们会想着走 else
这一段代码。而 else
里又是一个 if
判断:a == b
a > b
条件是不是成立的。如果不成立,就会继续判断 a == b
这个条件。因此,实际上这种写法就解决了前面说的,忘记判断 a == b
的问题。
不过,这个写法还是有点丑。C# 可以允许我们去掉 else
的大括号:
这个写法是没有问题的。C# 是知道,下方的 if
-else
是一个整体,因此不需要大括号就知道整个代码里的 else
就完整包含了下面一大坨内容。但是,实际上还是有点丑。不如我们把 else
后直接跟上 if
:
这样就很好了。从这个角度来说,我们一下就可以看出逻辑:先 a > b
;如果不满足就 a == b
;再不满足就执行最下面的 else
1-4 它和条件运算符的关联
最开始,我们说到过一个东西,叫条件运算符。条件运算符的逻辑完全类似于这里的 if
-else
的过程。不过问题在于,它们有区别吗?
条件运算符用来表示和赋值,因此 ?
后和 :
后的部分全都是一个表达式(所谓的表达式,就必须反馈一个结果数值出来;而语句则不一定要反馈结果,它可以像是 Console.WriteLine
那样,单独成一个语句来用)。而 if
-else
则可以跟语句或者是赋值表达式。我们来看一下。
这是将 a
和 b
较大的数值赋值给 c
的过程。如果要写成 if
-else
,就得这样:
或者直接写到一行上去:
不管怎么做,代码都比条件运算符要复杂。因此,我们建议用条件运算符而不是用 if
-else
1-5 永真和永假条件
有没有想过,既然这里我们传入的是一个 bool
的表达式,那么我们直接写 true
和 false
会如何。
或者
猜都猜得到,只要条件是 true
就会进去执行。因此 if (true)
等价于根本没写条件判断。而 if (false)
if
里面的语句永远都得不到执行。
Part 2 switch
的用法
很显然,前文的 if
-else
是无敌的。但是很遗憾的是,对于一些特殊的条件判断,if
-else
怎么写都很臃肿。比如我们输入一个月份数值,然后判断月份到底有多少天。那么用 if
就得这样:
我且不说其它的内容,就判断 month
的信息,也显得很臃肿。此时,我们这里介绍一个新的语法格式:switch
语句。
2-1 switch
语句
switch
语句的用法是这样的:
这个写法可能不是很好懂。我们直接上代码:
貌似……好像代码没有减少多少。不过更好看了,因为 month
直接写到 switch
上用来表示“我这里就是按 month
case
里写的就是 month
的所有可能数值。default
则表示当前面所有数值都不是 month
现在的数值的时候,就走这里。
请注意一下,每一个 case
语句最后,都要跟一个 break;
,这是因为这是为了让每一个 case
断层。C 语言里,没有写 break
就会导致执行的时候出现潜在的问题。C# 沿用了这种机制,但防止你误用代码,所以不写 break
会产生编译错误,提示你必须加了 break;
之后才能继续执行。C# 里,break;
语句遇到后,会自动跳出 switch
的内容。比如这个例子里,会自动跳转到第 27 行代码执行。
2-2 同执行语句简化
显然,我们发现当 1、3、5、7、8、10、12 月份的时候,day
都是 31;而当 4、6、9、11 的时候,day
都是 30。switch
还有一个强劲的功能就是,简化 case
。我们只看 switch
这一块,代码可以简化成这样:
这样的话,就更简单一些了。如果写 if
||
来连接条件。比如说第 3 行转成 if
就得写成这样:
显然,就很丑。
2-3 字符串的 switch
在 C# 里,因为有字符串这种类型,因此 switch
还可以对字符串进行判断。
case 字符串
的格式。确实,C# 也是允许这么做的。
由于字符串的每一个字符都不一样的关系,就算只有大小写不同的两个字符串也属于两个不同的字符串,因此我们这里在例子程序中是分开成两个情况作判断的。
2-4 很遗憾,布尔量没有 switch
这显然是废话。bool
类型的数值往往只有 true
和 false
两种可选情况,那么你要写成 switch
语句的话,你只能写成这样:
可问题在于,case true
和 case false
就已经构成了 bool
类型的所有可能取值的情况。那么,我是不是就意味着我可以把这里的 case false
替代为 default
呢?那么,我这么写和前文的语义是一样的吗?
如果真的是一样的,那么我这么写代码不就很奇怪了吗?
是的。考虑到这种写法的语义格式的复杂性,以及使用场景的问题,C# 并未对布尔型变量开放允许使用 switch
语句。虽然很遗憾,但也是合情合理的情况。
Part 3 混用 switch
和 if
前文我们没有判断 2 月份在平年还是闰年。如果我们加上这个判断的话,就这么写:
case
最后必须跟一个 break;
,因此就算我们写了一大坨东西,最后的 break;
也是不可少的。当然了,你也可以这么写:
这么写呢,就是长一点,但是用的是条件运算符。
Part 4 if
和 switch
的选择
如果你在写代码的时候,肯定会遇到“我到底用 if
好,还是 switch
好”的问题。有一个很好的判断标准是,。
比如前面的例子,我们对 month
进行数值的确认,显然是用 switch
更合理;但是如果是其它的情况,我们都应该采用 if
来表示。当然了,如果可能数值过多的话,我们就不建议用 switch
了。