C#基础-3-运算符与判断

前文:

运算符

包含算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符及其他运算符。

算数运算符

假设变量 A 的值为 10,变量 B 的值为 20,则:

运算符 描述 示例
+ A + B 将得到 30
- A - B 将得到 -10
* A * B 将得到 200
/ B / A 将得到 2
% 取模运算符,整除后的余数 B % A 将得到 0
++ 自增运算符,整数值增加 1 A++ 将得到 11
-- 自减运算符,整数值减去 1 A-- 将得到 9

对于 a++​ 和 ++a​ 的区别:( a--​ 同理)

int A = 5;
// 后置自增
int result1 = A++; // 先赋值,后自增
Console.WriteLine($"result1: {result1}, A: {A}");
// 输出:
result1: 5, A: 6

int A = 5;
// 前置自增
int result2 = ++A; // 先自增,后赋值
Console.WriteLine($"result2: {result1}, A: {A}");
// 输出:
result2: 6, A: 6

例如:

int a = 21;
int b = 10;
int c;

c = a + b;
Console.WriteLine($"Line 1 - c 的值是 {c}");
c = a - b;
Console.WriteLine($"Line 2 - c 的值是 {c}");
c = a * b;
Console.WriteLine($"Line 3 - c 的值是 {c}");
c = a / b;
Console.WriteLine($"Line 4 - c 的值是 {c}");
c = a % b;
Console.WriteLine($"Line 5 - c 的值是 {c}");

// ++a 先进行自增运算再赋值
c = ++a;
Console.WriteLine($"Line 6 - c 的值是 {c}");

// 此时 a 的值为 22
// --a 先进行自减运算再赋值
c = --a;
Console.WriteLine($"Line 7 - c 的值是 {c}");

输出:

关系运算符

假设变量 A 的值为 10,变量 B 的值为 20,则:

运算符 描述 示例
== 检查两个操作数的值是否相等,如果相等则条件为真 ( A == B​ ) 不为真
!= 检查两个操作数的值是否相等,如果不相等则条件为真 ( A != B​ ) 为真
> 检查左操作数的值是否大于右操作数的值,如果是则条件为真 ( A > B​ ) 不为真
< 检查左操作数的值是否小于右操作数的值,如果是则条件为真 ( A < B​ ) 为真
>= 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真 ( A >= B​ ) 不为真
<= 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真 ( A <= B​ ) 为真

示例:

int a = 21;
int b = 10;

if (a == b) {
	Console.WriteLine("Line 1 - a 等于 b");
} else {
	Console.WriteLine("Line 1 - a 不等于 b");
}
if (a < b) {
	Console.WriteLine("Line 2 - a 小于 b");
} else {
	Console.WriteLine("Line 2 - a 不小于 b");
}
if (a > b) {
	Console.WriteLine("Line 3 - a 大于 b");
} else {
	Console.WriteLine("Line 3 - a 不大于 b");
}

// 改变 a 和 b 的值
a = 5;
b = 20;
if (a <= b) {
	Console.WriteLine("Line 4 - a 小于或等于 b");
}
if (b >= a) {
	Console.WriteLine("Line 5 - b 大于或等于 a");
}

输出:

Line 1 - a 不等于 b
Line 2 - a 不小于 b
Line 3 - a 大于 b
Line 4 - a 小于或等于 b
Line 5 - b 大于或等于 a

逻辑运算符

假设变量 A 为布尔值 true​,变量 B 为布尔值 false​,则:

运算符 描述 示例
&& 与:如果两个操作数都非零,则条件为真 ( ​A && B ) 为假
|| 或:如果两个操作数中有任意一个非零,则条件为真 ( A || B​ ) 为真
! 非:逆转操作数的逻辑状态,如果条件为真则逻辑非运算符将使其为假 ​ ( !(A && B) ) 为真

示例:

bool a = true;
bool b = true;

if (a && b) {
	Console.WriteLine("Line 1 - 条件为真");
}
if (a || b) {
	Console.WriteLine("Line 2 - 条件为真");
}
// 改变 a 和 b 的值
a = false;
b = true;
if (a && b) {
	Console.WriteLine("Line 3 - 条件为真");
} else {
	Console.WriteLine("Line 3 - 条件不为真");
}
if (!(a && b)) {
	Console.WriteLine("Line 4 - 条件为真");
}

输出:

Line 1 - 条件为真
Line 2 - 条件为真
Line 3 - 条件不为真
Line 4 - 条件为真

位运算符

位运算符作用于位,并逐位执行操作。&​ 、 |​ 、 ^​ 的真值表如下所示:

p q ​​p & q p | q​​ p ^ q​​
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1

假设如果 A = 60,且 B = 13,二进制为:

A = 0011 1100
B = 0000 1101

则:

运算符 描述 实例
& 二进制 AND 运算符复制一位到结果中 ( A & B​ ) 将得到 12,即为 0000 1100
| 二进制 OR 运算符复制一位到结果中 ( A | B​ ) 将得到 61,即为 0011 1101
^ 二进制 运算符复制一位到结果中 ( A ^ B​ ) 将得到 49,即为 0011 0001
~ 一元运算符,具有"翻转"位效果,即0变成1,1变成0,包括符号位 ( ~A ) 将得到 -61,即为 1100 0011,一个有符号二进制数的补码形式
<< 二进制左移运算符,值向左移动指定的位数 ( A << 2 ) 将得到 240,即为 1111 0000
>> 二进制右移运算符,值向右移动指定的位数 ​​( A >> 2 ) 将得到 15,即为 0000 1111

示例:

int a = 60;    // 60 = 0011 1100
int b = 13;    // 13 = 0000 1101 */
int c = 0;

c = a & b;    // 12 = 0000 1100
Console.WriteLine($"Line 1 - c 的值是 {c}");

c = a | b;    // 61 = 0011 1101
Console.WriteLine($"Line 2 - c 的值是 {c}");

c = a ^ b;    // 49 = 0011 0001
Console.WriteLine($"Line 3 - c 的值是 {c}");

c = ~a;        // -61 = 1100 0011
Console.WriteLine($"Line 4 - c 的值是 {c}");

c = a << 2;    // 240 = 1111 0000
Console.WriteLine($"Line 5 - c 的值是 {c}");

c = a >> 2;    // 15 = 0000 1111
Console.WriteLine($"Line 6 - c 的值是 {c}");

输出:

Line 1 - c 的值是 12
Line 2 - c 的值是 61
Line 3 - c 的值是 49
Line 4 - c 的值是 -61
Line 5 - c 的值是 240
Line 6 - c 的值是 15

赋值运算符

运算符 描述 实例
= 简单的赋值运算符,把右边的值赋给左边 ​​C = A + B 将把 A + B 的值赋给 C
+= 加且赋值,把右边加上左边的结果赋值给左边 ​​C += A 相当于 C = C + A
-= 减且赋值,把左边减去右边的结果赋值给左边 C -= A​​ 相当于 C = C - A
*= 乘且赋值,把右边乘以左边的结果赋值给左边 C *= A​​ 相当于 C = C * A
/= 除且赋值,把左边除以右边的结果赋值给左边 ​​C /= A 相当于 C = C / A
%= 求模且赋值,求两个操作数的模赋值给左边 ​​C %= A 相当于 C = C % A
<<= 左移且赋值 ​​C <<= 2 等同于 C = C << 2
>>= 右移且赋值 C >>= 2​​ 等同于 C = C >> 2
&= 按位与且赋值 ​​C &= 2 等同于 C = C & 2
^= 按位异或且赋值 ​​C ^= 2 等同于​ C = C ^ 2
|= 按位或且赋值 ​​C |= 2 等同于 C = C | 2

示例:

int a = 21;
int c;

c = a;
Console.WriteLine($"Line 1 - =  c 的值 = {c}");

c += a;
Console.WriteLine($"Line 2 - += c 的值 = {c}");

c -= a;
Console.WriteLine($"Line 3 - -=  c 的值 = {c}");

c *= a;
Console.WriteLine($"Line 4 - *=  c 的值 = {c}");

c /= a;
Console.WriteLine($"Line 5 - /=  c 的值 = {c}");

c = 200;
c %= a;
Console.WriteLine($"Line 6 - %=  c 的值 = {c}");

c <<= 2;
Console.WriteLine($"Line 7 - <<=  c 的值 = {c}");

c >>= 2;
Console.WriteLine($"Line 8 - >>=  c 的值 = {c}");

c &= 2;
Console.WriteLine($"Line 9 - &=  c 的值 = {c}");

c ^= 2;
Console.WriteLine($"Line 10 - ^=  c 的值 = {c}");

c |= 2;
Console.WriteLine($"Line 11 - |=  c 的值 = {c}");

输出:

Line 1 - =     c 的值 = 21
Line 2 - +=    c 的值 = 42
Line 3 - -=    c 的值 = 21
Line 4 - *=    c 的值 = 441
Line 5 - /=    c 的值 = 21
Line 6 - %=    c 的值 = 11
Line 7 - <<=    c 的值 = 44
Line 8 - >>=    c 的值 = 11
Line 9 - &=    c 的值 = 2
Line 10 - ^=    c 的值 = 0
Line 11 - |=    c 的值 = 2

其他运算符

运算符 描述 实例
sizeof() 返回数据类型的大小 ​​sizeof(int) 将返回 4
typeof() 返回 class 的类型 typeof(StreamReader);​​
& 返回变量的地址 ​​&a; 将得到变量的实际内存地址
* 变量的指针 ​​*a; 将指向一个变量
?: 条件表达式 如果条件为真 ? 则为 X : 否则为 Y
is 判断对象是否为某一类型 ​​if( Ford is Car) 检查 Ford 是否是 Car 类的一个对象
as 强制转换,即使转换失败也不会抛出异常 Object obj = new StringReader("Hello"); StringReader r = obj as StringReader;

示例:

// sizeof 运算符的实例
Console.WriteLine($"int 的大小是 {sizeof(int)}");
Console.WriteLine($"short 的大小是 {sizeof(short)}");
Console.WriteLine($"double 的大小是 {sizeof(double)}");
     
// 三元运算符的实例
int a, b;
a = 10;
b = (a == 1) ? 20 : 30;
Console.WriteLine($"b 的值是 {b}");

b = (a == 10) ? 20 : 30;
Console.WriteLine($"b 的值是 {b}");

输出:

int 的大小是 4
short 的大小是 2
double 的大小是 8
b 的值是 30
b 的值是 20

typeof​ 关键字用于获取一个类型的类型对象,它通常用于反射和动态创建类型实例:

Type type = typeof(string);
Console.WriteLine(type.FullName);

使用 typeof​ 关键字来获取 string​ 类型的类型对象,并将其存储在 Type​ 类型的变量 type​ 中,然后,使用 FullName​ 属性打印该类型的完全限定名,输出:

System.String

运算符优先级

运算符的优先级确定表达式中项的组合,例如 x = 7 + 3 * 2​,在这里,x 被赋值为 13,而不是 20,因为运算符 *​ 具有比 +​ 更高的优先级

优先级简易概括:有括号先括号,后乘除在加减,然后位移再关系,逻辑完后条件,最后一个逗号 ,​ 。

图源自 菜鸟教程

算术运算符和赋值运算符的优先级:

int a = 10, b = 5, c = 2;
int result = a + b * c;  // 先计算乘法,再计算加法
Console.WriteLine(result);  // 输出20

result = (a + b) * c;     // 先计算加法,再计算乘法
Console.WriteLine(result);  // 输出30

a += b * c;               // 先计算乘法,再执行加法赋值
Console.WriteLine(a);       // 输出20

逻辑运算符的优先级:

bool a = true, b = false, c = true;
bool result = a || b && c;  // 先计算与运算,再计算或运算
Console.WriteLine(result);  // 输出true

result = (a || b) && c;     // 先计算或运算,再计算与运算
Console.WriteLine(result);  // 输出true

result = a || (b && c);     // 先计算与运算,再计算或运算
Console.WriteLine(result);  // 输出true

条件运算符的优先级:

int a = 10, b = 5;
string result = a > b ? "a大于b" : "a不大于b";  // 先判断大小关系,再执行条件语句
Console.WriteLine(result);  // 输出"a大于b"

注意:由于括号可以改变运算符优先级,所以在实际应用中建议尽可能使用括号来明确运算顺序,提高代码的可读性和准确性。

判断

判断结构要求程序员指定一个或多个要评估或测试的条件,以及条件为真时要执行的语句(必需的)和条件为假时要执行的语句(可选的)

if语句

用法:

if (布尔表达式)
{
   // 如果布尔表达式为真将执行的语句
}

如果布尔表达式为 true,则 if 语句内的代码块将被执行。如果布尔表达式为 false,则 if 语句结束后的第一组代码(闭括号后)将被执行,示例:

int a = 10;

// 使用 if 语句检查布尔条件
if (a < 20)
{
	// 如果条件为真,则输出下面的语句
	Console.WriteLine("a 小于 20");
}
// 如果条件不为真,则不执行,跳过 if 语句块,继续向下执行代码
Console.WriteLine($"a 的值是 {a}");

输出:

a 小于 20
a 的值是 10

if-else语句

if-else 用法:

if (布尔表达式)
{
   // 如果布尔表达式为真将执行的语句
}
else
{
  // 如果布尔表达式为假将执行的语句
}

示例:

int a = 100;

// 检查布尔条件
if (a < 20)
{
	// 如果条件为真,则输出下面的语句
	Console.WriteLine("a 小于 20");
}
else
{
	// 如果条件为假,则输出下面的语句
	Console.WriteLine("a 大于 20");
}
Console.WriteLine($"a 的值是 {a}");

输出:

a 大于 20
a 的值是 100

if-else if-else用法:

if(布尔表达式1)
{
   // 当布尔表达式 1 为真时执行
}
else if(布尔表达式2)
{
   // 当布尔表达式 2 为真时执行
}
else if(布尔表达式3)
{
   // 当布尔表达式 3 为真时执行
}
else 
{
   // 当上面条件都不为真时执行
}

注意事项:

  • if 后面可以跟 0 或者 多个 else if
  • else 必须在 else if 后面
  • 一旦某个 else if 匹配成功,其他的 else if 或 else 将不会被测试和执行

示例:

int a = 100;

// 检查布尔条件
if (a == 10)
{
	// 如果 if 条件为真,则输出下面的语句
	Console.WriteLine("a 的值是 10");
}
else if (a == 20)
{
	// 如果 else if 条件为真,则输出下面的语句
	Console.WriteLine("a 的值是 20");
}
else if (a == 30)
{
	// 如果 else if 条件为真,则输出下面的语句
	Console.WriteLine("a 的值是 30");
}
else
{
	// 如果上面条件都不为真,则输出下面的语句
	Console.WriteLine("没有匹配的值");
}
Console.WriteLine($"a 的准确值是 {a}");

输出:

没有匹配的值
a 的准确值是 100

嵌套 if,else if,顾名思义,就是套娃,用法:

if(布尔表达式1)
{
	// 当布尔表达式 1 为真时执行
	if(布尔表达式2)
	{
		// 当布尔表达式 2 为真时执行
		// 也就是说,这里的语句只有布尔表达式 1 和 2 都为真才执行
	}
}

示例:

int a = 100;
int b = 200;

// 检查布尔条件
if (a == 100)
{
	// 如果条件为真,则检查下面的条件
	if (b == 200)
	{
		// 如果条件为真,则输出下面的语句
		Console.WriteLine("a 的值是 100,且 b 的值是 200");
	}
}
Console.WriteLine($"a 的准确值是 {a}");
Console.WriteLine($"b 的准确值是 {b}");

输出:

a 的值是 100,且 b 的值是 200
a 的准确值是 100
b 的准确值是 200

switch语句

一个 switch 语句允许测试一个变量等于多个值时的情况,每个值称为一个 case,且被测试的变量会对每个 switch case 进行检查,用法:

switch (expression) {
	case constant-expression :
		statement(s);
		break;
	case constant-expression :
		statement(s);
		break; 
  
    // 可以有任意数量的 case 语句
	default : // 可选的
		statement(s);
		break; 
}

注意事项:

  • switch 语句中的 expression 必须是一个 整型或枚举类型,或者是一个 class 类型,其中 class 有一个单一的转换函数将其转换为整型或枚举类型
  • 在一个 switch 中可以有任意数量的 case 语句。每个 case 后跟一个要 比较的值和一个冒号
  • case 的 constant-expression 必须与 switch 中的变量具有 相同的数据类型,且必须是一个 常量
  • 当被测试的变量等于 case 中的常量时,case 后跟的语句将被执行,直到遇到 break 语句为止
  • 当遇到 break 语句时,switch 终止,控制流将跳转到 switch 语句后的下一行
  • 不是每一个 case 都需要包含 break。如果 case 语句为空,则可以不包含 break,控制流将会 继续 后续的 case,直到遇到 break 为止
  • C# 不允许从一个 case 部分继续执行到下一个 case 部分。如果 case 语句中有已经执行,则必须包含 break 或其他跳转语句
  • 一个 switch 语句可以有一个可选的 default 语句,在 switch 的结尾。default 语句用于在上面所有 case 都 不为 true 时 执行的一个任务。default 也需要包含 break 语句,这是一个良好的习惯。
  • C# 不支持从一个 case 标签显式贯穿到另一个 case 标签。如果要使 C# 支持从一个 case 标签显式贯穿到另一个 case 标签,可以使用 goto​ 一个 switch-case 或 goto default​ 。

示例1:

int day = 4;
switch (day)
{
	case 1:
		Console.WriteLine("Monday");
		break;
	case 2:
		Console.WriteLine("Tuesday");
		break;
	case 3:
		Console.WriteLine("Wednesday");
		break;
	case 4:
		Console.WriteLine("Thursday");
		break;
	case 5:
		Console.WriteLine("Friday");
		break;
	case 6:
		Console.WriteLine("Saturday");
		break;
	case 7:
		Console.WriteLine("Sunday");
		break;
	default :
		Console.WriteLine("日期错误");
		break;
} 

输出:

Thursday

示例2:

char grade = 'B';

switch (grade)
{
	case 'A':
		Console.WriteLine("很棒!");
		break;
	case 'B':
	case 'C':
		Console.WriteLine("做得好");
		break;
	case 'D':
		Console.WriteLine("您通过了");
		break;
	case 'F':
		Console.WriteLine("最好再试一下");
		break;
	default:
		Console.WriteLine("无效的成绩");
		break;
}
Console.WriteLine($"您的成绩是 {grade}");

输出:

做得好
您的成绩是 B

case B 内容为空,跳到了 case C,并且执行了 case C 中的语句,直到遇到了 case C 中的 break 才跳出 switch 语句。

switch 和 if 语句一样支持嵌套,可以把一个 switch 作为一个外部 switch 的语句序列的一部分,即可以在一个 switch 语句内使用另一个 switch 语句,即使内部和外部 switch 的 case 常量包含共同的值,也没有矛盾。例如:

int a = 100;
int b = 200;

switch (a)
{
	case 100:
		Console.WriteLine("这是外部 switch 的一部分");
		switch (b)
		{
			case 200:
				Console.WriteLine("这是内部 switch 的一部分");
				break;
		}
		break;
}
Console.WriteLine($"a 的准确值是 {a}");
Console.WriteLine($"b 的准确值是 {b}");

输出:

这是外部 switch 的一部分
这是内部 switch 的一部分
a 的准确值是 100
b 的准确值是 200

条件运算符

前文中的 ? :​ 运算符的功能和简单的 if else 的功能一样,例如:

int a, b;
a = 10;
b = (a == 1) ? 20 : 30;
Console.WriteLine($"b 的值是 {b}");

b = (a == 10) ? 20 : 30;
Console.WriteLine($"b 的值是 {b}");

输出:

b 的值是 30
b 的值是 20