4.2 分支
分支是控制下一步要执行哪行代码的过程。要跳转到的代码行由某个条件语句来控制。这个条件语句使用布尔逻辑,对测试值和一个或多个可能的值进行比较。
本节介绍C#中的3种分支技术:
● 三元运算符
● if语句
● switch语句
4.2.1 三元运算符
最简单的比较方式是使用第3章介绍的三元(或条件)运算符。一元运算符有一个操作数,二元运算符有两个操作数,所以三元运算符有3个操作数。其语法如下:
<test> ? <resultIfTrue>: <resultIfFalse>
其中,计算<test>可得到一个布尔值,运算符的结果根据这个值来确定是<resultIfTrue>还是<resultIfFalse>。
使用三元运算符可以测试int变量myInteger的值:
string resultString = (myInteger < 10) ? "Less than 10" : "Greater than or equal to 10";
三元运算符的结果是两个字符串中的一个,这两个字符串都可能赋给resultString。把哪个字符串赋给resultString,取决于myInteger的值与10的比较结果。如果myInteger的值小于10,就把第一个字符串赋给resultString;如果myInteger的值大于或等于10,就把第二个字符串赋给resultString。例如,如果myInteger的值是4,则resultString的值就是字符串"Less than 10"。
4.2.2 if语句
if语句的功能比较多,是有效的决策方式。与?:语句不同的是,if语句没有结果(所以不在赋值语句中使用它),使用该语句是为了根据条件执行其他语句。
if语句最简单的语法如下:
if (<test>) <code executed if <test> is true>;
先执行<test>(其计算结果必须是一个布尔值,这样代码才能编译),如果<test>的计算结果是true,就执行该语句之后的代码。这段代码执行完毕后,或者因为<test>的计算结果是false,而没有执行这段代码,将继续执行后面的代码行。
也可将else语句和if语句合并使用,指定其他代码。如果<test>的计算结果是false,就执行else语句:
if (<test>) <code executed if <test> is true>; else <code executed if <test> is false>;
可使用成对的花括号将这两段代码放在多个代码行上:
if (<test>) { <code executed if <test> is true>; } else { <code executed if <test> is false>; }
例如,重新编写上一节使用三元运算符的代码:
string resultString = (myInteger < 10) ? "Less than 10" : "Greater than or equal to 10";
因为if语句的结果不能赋给一个变量,所以要单独将值赋给变量:
string resultString; if (myInteger < 10) resultString = "Less than 10"; else resultString = "Greater than or equal to 10";
这样的代码尽管比较冗长,但与三元运算符相比,更便于阅读和理解,也更加灵活。
下面的示例演示了if语句的用法。
试一试:使用if语句:Ch04Ex02\Program.cs
(1)在目录C:\BegVCSharp\Chapter04中创建一个新的控制台应用程序Ch04Ex02。
(2)把下列代码添加到Program.cs中:
static void Main(string[] args) { string comparison; WriteLine("Enter a number:"); double var1 = ToDouble(ReadLine()); WriteLine("Enter another number:"); double var2 = ToDouble(ReadLine()); if (var1 < var2) comparison = "less than"; else { if (var1 == var2) comparison = "equal to"; else comparison = "greater than"; } WriteLine($"The first number is {comparison} the second number."); ReadKey(); }
(3)执行代码,根据提示输入两个数字,如图4-2所示。
图4-2
示例说明
我们已经十分熟悉代码的第一部分,它从用户输入中得到两个double值:
string comparison; WriteLine("Enter a number:"); double var1 = ToDouble(ReadLine()); WriteLine("Enter another number:"); double var2 = ToDouble(ReadLine());
接着根据var1和var2的值,将一个字符串赋给string变量comparison。首先看看var1是否小于var2:
if (var1 < var2) comparison = "less than";
如果不是,则var1大于或等于var2。在第一个比较操作的else部分,需要嵌套第二个比较:
else { if (var1 == var2) comparison = "equal to";
只有在var1大于var2时,才执行第二个比较操作中的else部分:
else comparison = "greater than"; }
最后将比较操作的值写到控制台:
WriteLine("The first number is {0} the second number.", comparison);
这里使用的嵌套只是进行这些比较的一种方式,还可以编写如下代码:
if (var1 < var2) comparison = "less than"; if (var1 == var2) comparison = "equal to"; if (var1 > var2) comparison = "greater than";
这种方式的缺点在于:无论var1和var2的值是什么,都要执行3个比较操作。在第一种方式中,如果var1 < var2是true,就只执行一个比较操作,否则就要执行两个比较操作(还执行了var1 == var2比较操作),这样将使执行的代码行较少。在本例中性能上的差异较小,但在较重视速度的应用程序中,性能的差异就很明显了。
使用if语句判断更多条件
在上面的示例中,检查了涉及var1的值的3个条件,包括这个变量所有可能的值。有时要检查特定的值,例如var1是否等于1、2、3或4等。使用上面那样的代码会得到很多烦人的嵌套代码:
if (var1 == 1) { // Do something. } else { if (var1 == 2) { // Do something else. } else { if (var1 == 3 || var1 == 4) { // Do something else. } else { // Do something else. } } }
警告:人们经常会错误地将诸如if(var1== 3 || var1 == 4)的条件写为if (var1 == 3 || 4)。由于运算符具有优先级,因此首先执行==运算符,接着用||运算符处理布尔和数值操作数,就会出现错误。
这些情况下,就要使用稍有不同的缩进模式,缩短else代码块(即在else块的后面使用一行代码而不是一个代码块),这样就得到了else if语句结构:
if (var1 == 1) { // Do something. } else if (var1 == 2) { // Do something else. } else if (var1 == 3 || var1 == 4) { // Do something else. } else { // Do something else. }
这些else if语句实际上是两个独立语句,它们的功能与上述代码相同,但更便于阅读。像这样进行多个比较的操作,应考虑使用另一种分支结构:switch语句。
4.2.3 switch语句
switch语句非常类似于if语句,因为它也是根据测试的值来有条件地执行代码。但是,switch语句可以一次将测试变量与多个值进行比较,而不是仅测试一个条件。这种测试仅限于离散的值,而不是像“大于X”这样的子句,所以它的用法有点不同,但它仍是一种强大的技术。
switch语句的基本结构如下:
switch (<testVar>) { case <comparisonVal1>: <code to execute if <testVar> == <comparisonVal1> > break; case <comparisonVal2>: <code to execute if <testVar> == <comparisonVal2> > break; .. case <comparisonValN>: <code to execute if <testVar> == <comparisonValN> > break; default: <code to execute if <testVar> ! = comparisonVals> break; }
<testVar>中的值与每个<comparisonValX>值(在case语句中指定)进行比较,如果有一个匹配,就执行为该匹配提供的语句。如果没有匹配,但有default语句,就执行default部分的代码。
执行完每个部分的代码后,还需要有另一个语句break。在执行完一个case块后,再执行第二个case语句是非法的。
注意:在此,C#与C++是有区别的。在C++中,可以在运行完一个case语句后,运行另一个case语句。
这里的break语句将中断switch语句的执行,而执行该结构后面的语句。
在C#代码中,还有其他方法可以防止程序流程从一个case语句转到下一个case语句。可以使用return语句,中断当前函数的运行,而不是仅中断switch结构的执行(详见第6章)。也可以使用goto语句(如前所述),因为case语句实际上是在C#代码中定义的标签。例如:
switch (<testVar>) { case <comparisonVal1>: <code to execute if <testVar> == <comparisonVal1> > goto case <comparisonVal2>; case <comparisonVal2>: <code to execute if <testVar> == <comparisonVal2> > break; ..
一个case语句处理完后,不能自由进入下一个case语句,但这条规则有一个例外。如果把多个case语句放在一起(堆叠它们),其后加一个代码块,实际上是一次检查多个条件。如果满足这些条件中的任何一个,就会执行代码,例如:
switch (<testVar>) { case <comparisonVal1>: case <comparisonVal2>: <code to execute if <testVar> == <comparisonVal1> or <testVar> == <comparisonVal2> > break; ..
注意,这些条件也适用于default语句。default语句不一定要放在比较操作列表的最后,还可以把它和case语句放在一起。用break或return添加一个断点,可确保在任何情况下,该结构都有一条有效的执行路径。
在下面的示例中,将使用switch语句,根据用户为测试字符串输入的值,将不同字符串写到控制台。
试一试:使用switch语句:Ch04Ex03\Program.cs
(1)在目录C:\BegVCSharp\Chapter04中创建一个新的控制台应用程序Ch04Ex03。
(2)把以下代码添加到Program.cs中:
static void Main(string[] args) { const string myName = "benjamin"; const string niceName = "andrea"; const string sillyName = "ploppy"; string name; WriteLine("What is your name? "); name = ReadLine(); switch (name.ToLower()) { case myName: WriteLine("You have the same name as me! "); break; case niceName: WriteLine("My, what a nice name you have! "); break; case sillyName: WriteLine("That's a very silly name."); break; } WriteLine($"Hello {name}! "); ReadKey(); }
(3)执行代码,输入一个姓名,结果如图4-3所示。
图4-3
示例说明
这段代码建立了3个常量字符串,接受用户输入的一个字符串,再根据输入的字符串把文本写到控制台。这里,字符串是用户输入的姓名。
在比较输入的姓名(在变量name中)和常量值时,首先要用name.ToLower()把输入的姓名转换为小写。name.ToLower()是一个标准命令,可用于处理所有字符串变量,在不能确定用户输入的内容时,使用它是很方便的。使用这个技术,字符串Benjamin、benJamin、benjamin等就会与测试字符串benjamin匹配了。
switch语句尝试将输入的字符串与定义的常量值进行匹配,如果成功,就会用一条个性化的消息问候用户。如果不匹配,则只简单地问候用户。