C# 7.0 核心技术指南 (50):C#语言基础 2.11.3

阅读数:6 2019 年 12 月 4 日 17:14

C# 7.0核心技术指南(50):C#语言基础 2.11.3

(选择语句)

内容简介
本书前三章将集中介绍 C#语言。首先介绍基本的语法、类型和变量。而后会介绍一些高级的特性,如不安全代码以及预处理指令。如果你是 C#语言的初学者,请循序渐进地阅读这些章节。
其余各章则涵盖了.NET Framework 的核心功能,包括 LINQ、XML、集合、并发、I/O 和网络、内存管理、反射、动态编程、特性、安全、应用程序域和原生互操作性等主题。第 6 章和第 7 章是后续主题的基础,除这两章之外,其余各章可以按照需要以任何顺序阅读。LINQ 相关的三个章节好按顺序阅读。其中的一些章节需要一些并发相关的知识,这些知识将在第 14 章中介绍。

C#使用以下几种机制来有条件地控制程序的执行流:

  • 选择语句(if、switch)
  • 条件语句(?:)
  • 循环语句(while、do…while、for 和 foreach)

本节介绍了两种最简单的结构:if-else 语句和 switch 语句。

2.11.3.1 if 语句

if 语句在 bool 表达式为真时执行其中的语句。例如:

复制代码
if (5 < 2 * 3)
Console.WriteLine ("true"); // true

if 中的语句可以是代码块:

复制代码
if (5 < 2 * 3)
{
Console.WriteLine ("true");
Console.WriteLine ("Let's move on!");
}

2.11.3.2 else 子句

if 语句之后可以紧跟 else 子句:

复制代码
if (2 + 2 == 5)
Console.WriteLine ("Does not compute");
else
Console.WriteLine ("False"); // False

在 else 子句中,能嵌套另一个 if 语句:

复制代码
if (2 + 2 == 5)
Console.WriteLine ("Does not compute");
else
if (2 + 2 == 4)
Console.WriteLine ("Computes"); // Computes

2.11.3.3 用大括号改变执行流

else 子句总是与它之前的语句块中紧邻的未配对的 if 语句结合。例如:

复制代码
if (true)
if (false)
Console.WriteLine();
else
Console.WriteLine ("executes");

语义上等价于:

复制代码
if (true)
{
if (false)
Console.WriteLine();
else
Console.WriteLine ("executes");
}

可以通过改变大括号的位置来改变执行流:

复制代码
if (true)
{
if (false)
Console.WriteLine();
}
else
Console.WriteLine ("does not execute");

大括号可以明确表明结构,这能提高嵌套 if 语句的可读性(虽然编译器并不需要)。需要特别指出的是下面的模式:

复制代码
static void TellMeWhatICanDo (int age)
{
if (age >= 35)
Console.WriteLine ("You can be president!");
else if (age >= 21)
Console.WriteLine ("You can drink!");
else if (age >= 18)
Console.WriteLine ("You can vote!");
else
Console.WriteLine ("You can wait!");
}

这里,我们参照其他语言的 elseif 结构(以及 C#本身的#elif 预处理指令)来安排 if 和 else 语句。Visual Studio 自动识别这个模式并保持代码缩进。从语义上讲,紧跟着每一个 if 语句的 else 语句从功能上都是嵌套在 else 子句之中的。

2.11.3.4 switch 语句

switch 语句可以根据变量可能的取值来转移程序的执行。switch 语句可以拥有比嵌套 if 语句更加简洁的代码,因为 switch 语句仅仅需要一次表达式计算,例如:

复制代码
static void ShowCard (int cardNumber)
{
switch (cardNumber)
{
case 13:
Console.WriteLine ("King");
break;
case 12:
Console.WriteLine ("Queen");
break;
case 11:
Console.WriteLine ("Jack");
break;
case -1: // Joker is -1
goto case 12; // In this game joker counts as queen
default: // Executes for any other cardNumber
Console.WriteLine (cardNumber);
break;
}
}

这个例子演示了最一般的情形,即针对常量的 switch。当指定常量时,只能指定内置的整数类型、bool、char、enum 类型以及 string 类型。

每一个 case 子句结束时必须使用某种跳转指令显式指定下一个执行点(除非你的代码本身就是一个无限循环)。这些跳转指令有:

  • break(跳转到 switch 语句的最后)
  • goto case x(跳转到另外一个 case 子句)
  • goto default(跳转到 default 子句)
  • 其他的跳转语句,例如 return、throw、continue 或者 goto label

当多个值要执行相同的代码时,可以按照顺序列出共同的 case 条件:

复制代码
switch (cardNumber)
{
case 13:
case 12:
case 11:
Console.WriteLine ("Face card");
break;
default:
Console.WriteLine ("Plain card");
break;
}

switch 语句的这种特性可以写出比多个 if-else 更加简洁的代码。

2.11.3.5 带有模式的 switch 语句(C# 7)

C# 7 开始支持按类型 switch:

复制代码
static void Main()
{
TellMeTheType (12);
TellMeTheType ("hello");
TellMeTheType (true);
}
static void TellMeTheType (object x) // object allows any type.
{
switch (x)
{
case int i:
Console.WriteLine ("It's an int!");
Console.WriteLine ($"The square of {i} is {i * i}");
break;
case string s:
Console.WriteLine ("It's a string");
Console.WriteLine ($"The length of {s} is {s.Length}");
break;
default:
Console.WriteLine ("I don't know what x is");
break;
}
}

(object 类型允许其变量为任何类型。这部分内容将在 3.2 节和 3.3 节详细讨论。)

每一个 case 子句都指定了一种需要匹配的类型和一个变量(模式变量),如果类型匹配成功就对变量赋值。和常量不同,对于类型的使用并没有任何限制。

还可以使用 when 关键字对 case 进行预测,例如:

复制代码
switch (x)
{
case bool b when b == true: // Fires only when b is true
Console.WriteLine ("True!");
break;
case bool b:
Console.WriteLine ("False!");
break;
}

case 子句的顺序会影响类型的选择(这和选择常量的情况有些不同)。如果交换 case 的顺序,则上述示例可以得到完全不同的结果(事实上,上述程序甚至无法编译,因为编译器发现第二个 case 子句是永远不会执行的)。但 default 子句是一个例外,不论它出现在什么地方都会在最后才执行。

堆叠多个 case 子句也是没有问题的。下面的例子中,Console.WriteLine 会在任何浮点类型的值大于 1000 时执行:

复制代码
switch (x)
{
case float f when f > 1000:
case double d when d > 1000:
case decimal m when m > 1000:
Console.WriteLine ("We can refer to x here but not f or d or m");
break;
}

上述例子中,编译器仅允许在 when 子句中使用模式变量 f、d 和 m。当调用 Console.WriteLine 时,我们并不清楚到底三个模式变量中的哪一个会被赋值,因而编译器会将它们放在作用域之外。

除此以外,还可以混合使用常量选择和模式选择, 甚至可以选择 null 值:

复制代码
case null:
Console.WriteLine ("Nothing here");
break;

C# 7.0核心技术指南(50):C#语言基础 2.11.3

购书地址 https://item.jd.com/12681788.html?dist=jd

评论

发布