第10章 语句 笔记
第10章 语句 笔记
10.1 什么是语句
语句是描述某个类型或让程序执行某个动作的源代码指令。
主要有3种类型:
声明语句 声明类型或变量
嵌入语句 执行动作或管理控制流
标签语句 控制跳转
简单语句由一个表达式、分号组成
块是一对大括号括起来的语句序列,语句包括:声明语句、嵌入语句、标签语句、嵌套块。
空语句仅由一个分号组成,当程序逻辑不需要任何动作需要嵌入空语句。
int x = 10; // Simple declaration
int z; // Simple declaration
{ // Start of a blockint y = 20; // Simple declarationz = x + y; // Embedded statementtop: y = 30; // Labeled statement...{ // Start of a nested block...} // End of nested block
} // End of outer blockif( x < y ); // Empty statement
elsez = a + b; // Simple statement
10.2 表达式语句
表达式返回值有副作用,对许多表达式求值只是为了它们的副作用。
x = 10;
1
- 该表达式将 10 赋给 x,虽然这可能是语句的主要动机,但却归类为副作用。
- 设置 x 值后,表达式返回 x 的新值 10,但这个结果被忽略了。
10.3 控制流语句
- 条件执行语句,根据条件执行或跳过一个代码片段
- if
- if … else
- switch
- 循环语句,重复执行一个代码片段
- while
- do
- for
- foreach
- 跳转语句,从一个代码片段到另一个代码片段
- break
- continue
- return
- goto
- throw
10.4 if 语句
按条件执行,语法如下
if( TestExpr )Statement
10.5 if … else 语句
双路分支,语法如下
if( TestExpr )Statement1
elseStatement2
10.6 while 循环
简单循环结构,表达式在循环的顶部执行
while( TestExpr )Statement
int x = 3;
while( x > 0 )
{Console.WriteLine($"x: { x }");x--;
}
Console.WriteLine("Out of loop");
10.7 do 循环
简单循环结构,测试表达式在循环的底部执行
doStatement
while( TestExpr ); // End of do loop
int x = 0;
doConsole.WriteLine($"x is {x++ }");
while (x<3);
10.8 for 循环
测试表达式在循环体顶部计算返回true,for循环会执行循环体。
如果 TestExpr 为空,则测试一直返回 true。
for( Initializer ; TestExpr ; IterationExpr )Statement
for( int i=0 ; i<3 ; i++ )Console.WriteLine($"Inside loop. i: { i }");
Console.WriteLine("Out of Loop");
10.8.1 for 语句中变量的作用域
任何声明在 initializer 中的变量只在该 for 语句的内部可见。
for( int i=0; i<10; i++ ) // Variable i is in scope here, and alsoStatement; // here within the statement.
// Here, after the statement, i no longer exists.
// Type is needed here again because the previous variable i has gone out of existence.for(int i=0; i<10; i++ ) // We need to define a new variable i here,Statement; // the previous one has gone out of existence.
循环变量常用标识符 i、j、k
10.8.2 初始化和迭代表达式中的多表达式
可以包含多个表达式,用逗号隔开
static void Main( )
{const int MaxI = 5;// Two declarations Two expressionsfor (int i = 0, j = 10; i < MaxI; i++, j += 10){Console.WriteLine($"{ i }, { j }");}
}
10.9 switch 语句
switch语句实现多路分支。
switch语句有一个测试表达式或匹配表达式的参数,必须是以下数据类型:char、string、bool、integer、enum,C# 7.0 允许 TestExpr 为任何类型。
包含0个或多个分支块
每个分支块以一个或多个分支标签开头
switch 语句使用深度比较。
- 如果 TestExpr 和 PatternExpression 均为整数类型,C# 使用
==
比较。 - 否则,使用静态方法
Object.Equals(TestExpr, PatternExpression)
比较。
每个分支块遵守不穿过规则,分支块中的语句不能达到终点并进入下一个分支块,goto 不能和 switch 一起使用。
跳转语句包括:break、return、continue、goto、throw
分支块按顺序执行
default 分支可选,如果包括则必须以一条跳转语句结束。
10.9.1 分支示例
for( int x=1; x<6; x++ )
{switch( x ) // Evaluate the value of variable x.{case 2: // If x equals 2Console.WriteLine($"x is { x } -- In Case 2");break; // Go to end of switch.case 5: // If x equals 5Console.WriteLine($"x is { x } -- In Case 5";break; // Go to end of switch.default: // If x is neither 2 nor 5Console.WriteLine($"x is { x } -- In Default case");break; // Go to end of switch.}
}
10.9.2 其他类型的模式表达式
case标签由关键字case和后面的模式构成
public abstract class Shape { }
public class Square : Shape
{public double Side {get; set;}
}
public class Circle : Shape
{public double Radius {get; set;}
}
public class Triangle : Shape
{public double Height {get; set;}
}
class Program
{static void Main(){var shapes = new List<Shape>();shapes.Add(new Circle() { Radius = 7 });shapes.Add(new Square() { Side = 5 });shapes.Add(new Triangle() { Height = 4 });var nullSquare = (Square)null;shapes.Add(nullSquare);foreach (var shape in shapes ){switch( shape ) //Evaluate the type and/or value of variable shape.{case Circle circle: //Equivalent to if(shape is Circle)Console.WriteLine($"This shape is a circle of radius { circle.Radius }");break; case Square square when square.Side > 10: //Matches only a subset of SquaresConsole.WriteLine($"This shape is a large square of side { square.Side }");break;case Square square: Console.WriteLine($"This shape is a square of side { square.Side }");break;case Triangle triangle: // Equivalent to if(shape is Triangle)Console.WriteLine($"This shape is a triangle of side { triangle.Height }");break;//case Triangle triangle when triangle.Height < 5: //Compile error//Console.WriteLine($"This shape is a triangle of side { triangle.Height }");//break;case null: Console.WriteLine($"This shape could be a Square, Circle or a Triangle");break;default:throw new ArgumentException(message: "shape is not a recognized shape",paramName: nameof(shape)); }}}
}// output
This shape is a circle of radius 7
This shape is a square of side 5
This shape is a triangle of side 4
This shape could be a Square, Circle or a Triangle
10.9.3 switch 语句的补充
switch语句可以有任意数目的分支,也可以没有分支。
default也不是必须的。
10.9.4 分支标签
case后面的表达式可以是任何类型的模式
10.10 跳转语句
当控制流到达跳转语句时,程序执行被无条件地转移到程序的另一部分。
跳转语句包括:
break、continue、return、goto、throw
10.11 break 语句
break语句用于跳出最内层封装语句
int x = 0;
while( true )
{x++;if( x >= 3 )break;
}
10.12 continue 语句
continue 跳转到循环的最内层封装语句的顶端
for( int x=0; x<5; x++ ) // Execute loop five times
{if( x < 3 ) // The first three timescontinue; // Go directly back to top of loop// This line is only reached when x is 3 or greater.Console.WriteLine($"Value of x is { x }");
}
10.13 标签语句
标签语句由标识符、冒号、一条语句组成。
Identifier: Statement
标签语句仅执行 Statement 部分,就如同标签不存在一样。
标签语句只允许用在块内部
10.13.1 标签
标签有自己的声明空间,可与变量重名。
标签名不能是关键字。
重叠范围内标签名不能重复。
{int xyz = 0; // Variable xyz// ...xyz: Console.WriteLine("No problem."); // Label xyz
}
10.13.2 标签语句的作用域
标签语句的作用域为:
- 其声明所在的块。
- 声明块内部嵌套的块。
static void Main( )
{ // Scope A{ // Scope Bincrement: x++;{ // Scope C{ // Scope D// …} // Scope E// …}// …}end: Console.WriteLine("Exiting");
}
10.14 goto 语句
goto语句 无条件地跳转到标签语句
goto Identifier ;
- goto 可以跳入其所在块内的任何标签语句。
- goto 可以跳出到任何嵌套它的块内。
- goto 不能跳入所在块的内部块(避免部分条件判断缺失造成程序紊乱)。
使用 goto 语句是非常不好的!
bool thingsAreFine;
while (true)
{thingsAreFine = GetNuclearReactorCondition();if ( thingsAreFine )Console.WriteLine("Things are fine.");elsegoto NotSoGood;
}
NotSoGood: Console.WriteLine("We have a problem.");
10.15 using 语句
资源:指实现了 System.IDisposable 接口的类或结构。该接口仅有一个 Dispose 的方法。
使用资源的阶段:
- 分配资源。
- 使用资源。
- 处置资源。
如果使用资源时发生运行时错误,那么处置资源的代码可能无法执行。
10.15.1 包装资源的使用
using 语句帮助减少运行时错误带来的潜在问题,简洁地包装了资源的使用。
第一种形式
- 圆括号内分配资源。
- Statement 使用资源。
- using 语句隐式产生处置资源的代码。
using ( ResourceType Identifier = Expression ) Statement
使用 using 语句的效果如下:
- 分配资源。
- 将 Statement 放入 try 块。
- 创建资源的 Dispose 方法,并放入 finally 块。
using ( ResourceType Resource = new ResourceType(...) ) Statement// 等价于
{ResourceType Resource = new ResourceType(...);try{// Statement}finally{// Dispose of resource}
}
10.15.2 using 语句的示例
using System; // using DIRECTIVE; not using statement
using System.IO; // using DIRECTIVE; not using statementnamespace UsingStatement
{class Program{static void Main( ){ // using statementusing (TextWriter tw = File.CreateText("Lincoln.txt") ){tw.WriteLine("Four score and seven years ago, ...");}// using statementusing (TextReader tr = File.OpenText("Lincoln.txt")){string InputString;while (null != (InputString = tr.ReadLine()))Console.WriteLine(InputString);}}}
}
10.15.3 多个资源和嵌套
使用相同类型的多个资源语法如下:
using ( ResourceType Id1 = Expr1, Id2 = Expr2, ... ) EmbeddedStatement
static void Main()
{using (TextWriter tw1 = File.CreateText("Lincoln.txt"),tw2 = File.CreateText("Franklin.txt")){tw1.WriteLine("Four score and seven years ago, ...");tw2.WriteLine("Early to bed; Early to rise ...");}using (TextReader tr1 = File.OpenText("Lincoln.txt"),tr2 = File.OpenText("Franklin.txt")){string InputString;while (null != (InputString = tr1.ReadLine()))Console.WriteLine(InputString);while (null != (InputString = tr2.ReadLine()))Console.WriteLine(InputString);}// 嵌套使用using ( TextWriter tw1 = File.CreateText("Lincoln.txt") ){tw1.WriteLine("Four score and seven years ago, ...");using ( TextWriter tw2 = File.CreateText("Franklin.txt") ) // Nestedtw2.WriteLine("Early to bed; Early to rise ..."); // Single}}
10.15.4 using 语句的另一种形式
using ( Expression ) EmbeddedStatement
TextWriter tw = File.CreateText("Lincoln.txt"); // Resource declared
using ( tw ) // using statementtw.WriteLine("Four score and seven years ago, ...");
- 这种形式也能确保使用完资源后调用 Dispose 方法。
- 后续代码可能仍使用该资源,这将导致状态错误,因此不推荐使用该形式。
10.16 其他语句
在其他章中阐述的语句
语句 | 描述 |
---|---|
checked、unchecked | 控制溢出检查上下文 |
foreach | 遍历一个集合的每个成员 |
try、throw、finally | 处理异常 |
return | 将控制返回到调用函数的成员,而且还能返回一个值 |
yield | 用于迭代 |