C#深入浅出之操作符和控制流程
操作符
操作符简单举例就是生活中的+-*/等等运算符号,下面会详细讨论运算符内容。
一元正负操作符
有时候需要改变数值的正负号。一元操作符(-)可以使得数字的正负号改变。
例如: int a = -114514
一元操作符等价于从零减去操作数。对应的也有一元操作符(+),不过这个操作符可以说是多余的。
二元算术操作符
二元操作符有: +、-、*、/、%。
在C#当中,只有赋值、调用、递增、递减、await和对象创建表达式才能作为独立语句使用。
下面分别介绍各项的作用:
- +:加法运算
- -:减法运算
- *:乘法运算
- /:除法运算
- %:求余运算(取模)
操作符的执行顺序取决于它们的优先级和结合性。
- *、/、%拥有最高优先级。
- +和-具有降低优先级。
- =在6个操作符中优先级最低。
- 添加括号可以改变运算顺序,与数学运算一致。
- 操作数总是从左到右求值。
复合赋值操作符
符合赋值操作符表是将常见的二元操作符与赋值操作符结合起来。
int x =123;
x += 114514;
上述为复合赋值操作符用法,其他同理。
递增和递减操作符
C#提供一种特殊的一元操作符来实现及数据的递增和递减。
++:为操作数加一。
--:为操作数减一。
其中需要注意的是。递增和递减操作符的前缀使用和后缀使用。
int x = 114514;
System.Console.WriteLine($"{x++},{++x},{x}");
//Console: 114514,114516,114516
前缀递增显示的是递增结束后的值,而后缀递增则是显示递增开始之前的值。但是二者的最终结果都是操作数加一。
常量表达式和常量符号
可用操作符将多个字面值合并到常量表达式中。
const关键字的作用就是声明产量符号。因为常量不可变,在后续的代码中尝试对其进行修改都会报错。
const int ye = 114 * 514;
//常量表达式
const int er = ye * 2;
//常量
控制流程概述
if语句
if语句是C#最常见的语句之一。它对称为条件的布尔表达式进行求值,条件为true将执行后续语句。if语句可以有else子句,其中包含在条件为false时执行的代替语句。
if(flag)
consequence-statement
else
alternative-statement
嵌套if
代码有时候需要多个if语句。为了面对这个情况,if之内是可以再次声明if,进行多重嵌套。
if(flag):
codeBlock;
if(flag1):
codeBlock1;
....
为了分清嵌套结构,代码进行缩进,空白并不影响执行路径,但是我们需要要考虑代码的可读性。
if/else连贯格式如下:
if(input == 1)
System.Console.WriteLine(1);
else if(input == 2)
System.Console.WriteLine(2);
else if (input == 3)
System.Console.WriteLine(3);
else
System.Console.WriteLine(4);
无论哪一种情况,都应该选择代码最易读的格式。
代码块
在前面的if语句当中,if和else之后直接跟随了一个语句。这种情况只有在执行语句只有一行的时候可以使用。
可用大括号将多个语句合并成代码块,以实现在符合条件时执行多个语句。如:
if(input >9){
int a = 100;
Console.WriteLine(a);
}
建议在任何情况下,都采用后者大括号将多个语句合并成代码块的语法方式来进行代码的书写。避免不必要的语法错误,也可增加自己的代码的可读性。
代码块、作用域和声明空间
代码块经常被称为作用域。但是两个术语并不完全相等。具名事物的作用域是源代码的一个区域。可在该区域使用非限定名称引用该事物。局部变量的作用域就是封闭它的代码块。所以代码块经常会被称为“作用域”。
声明空间是具名事物的逻辑容器。该容器中不能存在同名的两个事物。代码块不仅定义了作用域,还定义了局部变量声明空间。在同一个声明空间中,不允许声明两个同名的局部变量。在声明局部变量的代码块外部,没有办法用局部变量的名称引用它,这时候会提示“超出作用域”。
声明空间覆盖所有子代码块。C#禁止编译一个代码块中声明的局部变量在其子代码块中重复声明。
布尔表达式
条件,也就是布尔表达式。如 if( input > 1 )
括号内的内容即布尔表达式。求值永远是true或false,在C#当中,布尔表达式必须返回bool值。
关系操作符和相等性操作符
用于判断一个值是否大于、小于或者等于另外一个值。它们都是二元操作符。
运算符 | 说明 | 示例 |
---|---|---|
< | 小于 | input < 1 |
> | 大于 | input > 1 |
<= | 小于或等于 | input <= 1 |
>= | 大于或等于 | input >= 1 |
== | 等于 | input == 1 |
!= | 不等于 | input != 1 |
逻辑操作符
- OR操作符(||):
||操作符对两个表达式求值,任何一个为true就返回true。
if(x > 1 || y <6){
codeBlock;
}
- AND操作符(&&):
&&操作符在两个操作数都为true的情况下才返回true。任何操作数为false都会返回false。
if(x > 1 && y <6){
codeBlock;
}
- XOR操作符(^):
运用于两个布尔操作数的情况下,只有在两个操作数仅有一个为true的前提下,XOR操作符才会返回true。
逻辑求反操作符
逻辑求反操作符(!)有时也称为NOT操作符,作用是反转一个bool操作类型的值。
bool valid = true;
bool result = !valid;
//Console:result = false
条件操作符
条件操作符(?:)为三元操作符,需要三个操作数,常规格式如下:
codition ? consequence : alternative
所表达的意思为:若codition求值为true,则操作符只求值consequence;否则只求值alternative。并且支持短路求值,顺序从左到右。
consequence与alternative的类型必须一致。
空合并操作符
空合并操作符??能简单表示“如果这个值为空,就是用另一个值”:
expression1??expression2
支持短路求值。如expression1不为null,就返回expression1的值,另一个表达式不求值。如果expression1求值为null,就返回expression2的值。空合并操作符属于二元操作符。
空条件操作符
对空值进行方法调用,都会抛出一个空值异常,说明程序逻辑肯定出错了。为此C#6.0引入了 ?. 操作符,称为空条件操作符或空传播操作符。
args?.Length == 0
等价于以下代码:
(args != null) ? (int?)args.Length : null
空条件操作符最方便之处在于可“链接”,以下举例:
args[0]?.ToLower().StartsWith(...)
上述例子如果在第一个操作数为空,整个表达式会被短路,调用链中不再发生其他调用。
注意不要遗漏额外的空条件操作符!!!!
另一个重点:用于返回值类型的成员时,总是返回该类型的可空版本。(如:返回 int? 而不是 int )
此外,空条件操作符也可与索引操作符连用,例如:
string first = args?[0];
意思是只有args非空,才会对变量赋值,否则赋值null。
但是上述例子需要注意!他表示的意思是只要args非空就一定存在元素,但是会存在特殊清空,数组非空的情况下也不一定会存在元素。为此我们应该避免和索引操作符组合使用空条件操作符。
按位操作符
该操作符用于处理二进制形式的值。
位移操作符
位移操作符(<<、>>、<<=、>>=),有时候需要将一个数的二进制值向左或者向右移。左移时,所有位都向左移动由操作符右侧的操作数指定的位数。移位后在右。边留下的空位由零填充。右移同理。但如果移动的是复苏,左侧填充1而不是0。两个唯一操作符是>>和<<,分别是右移操作符和左移操作符。
int x = -7;
x = (-7 >> 2); // 1111 1111 1111 1001
// 1111 1111 1111 1110
//x = -2
按位操作符
按位操作符(&、|、^),分别对应AND,OR,XOR。
byte and,or,xor;
and = 12 & 7; //and = 4
or = 12 | 7; //or = 15
xor = 12 ^ 7; //xor = 11
按位操作数不支持短路求值,即使左边的操作数为false,两边都会进行求值。
按位复合操作符
按位操作符也可以与赋值操作合并,即&=、|=和^=。
and &= 1;//and = and & 1
or |= 1;// or = or | 1
xor ^= 1;// xor = xor ^ 1
按位取反操作符
按位取反操作数反转操作数的每一位,操作数可以是int、uint、long和ulong类型。如~1返回1111 1111 1111 1111 1111 1111 1111 1110。
控制流程语句
while和do/while循环
它是最简单的条件循环。
while(condition):
statement
condition必须是布尔表达式,只要它求值为true,作为循环主体的语句(statement)就会反复执行下去。条件求值为false,就跳过循环主体,从它之后的语句开始执行。
do/while循环与while循环非常相似,区别在于循环主体至少执行一次。do/while的常规结构如下:
do{
statement
}while(condition)
for循环
for循环反复执行代码块直至满足指定条件。for循环有一套内建的语法规定了如何初始化,递增以及测试一个计数器的值。该计数器称为循环变量。由于循环语法中专门有一个位置是为递增/递减操作保留的,所以递增/递减操作符经常为for循环的一部分使用。
举例:
/*
for(int i = 0; i < 10; i++){
statement
}
*/
for(initial; condition; loop){
statement
}
initial(初始化)执行首次迭代前的初始化操作。
condition(条件)指定循环结束条件。
loop(循环)表达式在每次迭代后求值。
statement是在条件表达式为true时执行的循环主体。
for(;;){ ... }
完全有效,只要想办法从循环中跳出即可,缺失的条件默认为产量true。
for循环也可使用多个表达式,这里不详细说明。
foreach循环
C#最后一个循环语句是foreach,它遍历数据项集合,设置循环变量来依次表示其中每一项。循环主体对数据项执行指定操作。foreach循环的特点是每一项只遍历一次:不会出现越界报错。
foreach(type variable in collection){
statement
}
type为代表collection中每一项的variable声明数据类型。
variable是只读变量,foreach循环自动将collection中的下一项赋值给它。
collection是代表多个数据项的表达式,比如数组。
foreach循环期间禁止修改循环变量,因为循环变量是只读内容。
基本switch语句
一个值和多个常量值比较,switch比if语句更容易理解。
switch(expression){
case constant:
statement;
break;
default:
statement;
}
expression是要和不同常量比较的值。
constant是和主导类型兼容的任何产量表达式。
一个或者多个case标签(或者default标签),后跟一个或多个语句。
每一个statement语句的结束点都必须接上跳转语句,如:break、return。
跳转语句
循环的执行路径可改变,事实上,可用跳转语句退出循环。
break语句
任何时候遇到break语句,控制都会立即离开循环或switch。
continue语句
contiue语句跳转到当前迭代的末尾,并开始下一次迭代。C#的contiue语句允许退出当前迭代并跳到循环条件。如果循环条件为true,循环继续。
小结
本节介绍了C#赋值和算数运算符。如何使用操作符和const关键字声明变量。