C#初级语法–运算符、表达式、控制语句

通俗解释:运算符与表达式 —— “数学符号的代码版”

1. 核心比喻

运算符 → 像计算器上的按键(+-×÷)。
表达式 → 用运算符拼出的数学式子(比如 1 + 2)。

2. 四类常用运算符

(1) 算术运算符:加减乘除
符号 作用 示例 结果
+ 加法 3 + 2 5
- 减法 5 - 1 4
* 乘法 2 * 3 6
/ 除法 10 / 2 5
% 取余(模) 10 % 3 1
int 钱包 = 100;
int 花费 = 40;
int 剩余 = 钱包 - 花费; // 表达式:100 - 40 = 60 
(2) 比较运算符:判断大小
符号 作用 示例 结果(布尔值)
> 大于 5 > 3 true
< 小于 2 < 1 false
== 等于 3 == 3 true
!= 不等于 4 != 4 false
bool 是否买得起 = 钱包 >= 花费; // 检查钱包是否≥花费 
(3) 逻辑运算符:且/或/非
符号 作用 示例 结果
&& 且(两者都真) true && false false
` ` 或(至少一个真)
! 非(取反) !true false
bool 有会员 = true;
bool 打折日 = false;
bool 能打折 = 有会员 && 打折日; // false(需要同时满足)
(4) 赋值运算符:存结果
符号 作用 示例 等价于
= 赋值 a = 5
+= 先加后赋 a += 3 a = a + 3
++ 自增1(常用在循环) a++ a = a + 1
int 计数器 = 0;
计数器++; // 计数器变成1 
计数器 += 10; // 计数器变成11 

3. 表达式的组合

表达式可以像搭积木一样组合:

int a = 5;
int b = 10;
bool 结果 = (a * 2 > b) && (b % 2 == 0); 
// 计算步骤:
// 1. a * 2 → 10 
// 2. 10 > b → false 
// 3. b % 2 → 0 
// 4. 0 == 0 → true 
// 5. false && true → false 

4. 实际应用场景

(1) 游戏伤害计算
int 基础伤害 = 50;
int 暴击倍数 = 2;
bool 是否暴击 = 随机数.Next(0, 100) > 90; // 10%概率暴击 
int 最终伤害 = 是否暴击 ? 基础伤害 * 暴击倍数 : 基础伤害;
(2) 用户登录验证
string 输入账号 = "admin";
string 输入密码 = "123456";
bool 登录成功 = (输入账号 == "admin") && (输入密码 == "123456");
(3) 循环计数器
for (int i = 0; i < 10; i++) 
{
    Console.WriteLine(i); // 打印0到9 
}
// i++ 就是 i = i + 1 的简写 

5. 运算符优先级(谁先算)

当表达式混合多种运算符时,计算顺序如下:

() 括号优先
! ++ --(逻辑非、自增自减)
* / %
+ -
> < >= <=
== !=
&&
||

示例

int 结果 = 5 + 3 * 2; // 先算3*2=6,再5+6=11(乘法的优先级比加法高)

6. 特殊运算符

运算符 作用 示例
?: 三元运算符(简化if-else) int 最大 = a > b ? a : b;
?? 空值检查 string 名字 = 输入 ?? "匿名";
??= 空值时赋值 名字 ??= "无名";
int 分数 = 85;
string 评级 = 分数 >= 60 ? "及格" : "不及格"; // 相当于if-else的简写 

总结口诀

🔹 加减乘除算术符,比较结果真或假
🔹 且或非逻辑组合,赋值自增简写法
🔹 括号优先别搞错,三元运算替if-else
🔹 表达式像搭积木,步骤拆解不迷糊

就像做数学题:
运算符 → 加减乘除符号
表达式 → (1 + 2) × 3
优先级 → 先乘除后加减,括号最优先

黄金法则

不确定优先级时加()
逻辑运算注意短路效应(&&遇到false就停止)
自增(++)在前在后效果不同(a++ vs ++a

通俗解释:赋值运算符 —— “给变量贴标签”

1. 核心比喻:贴标签

变量就像空盒子(比如int 钱;)。
赋值运算符(=就是往盒子里贴标签,比如:

钱 = 100;  // 给"钱"这个盒子贴上"100"的标签 

2. 基础赋值(=

string 名字 = "小明";  // 把"小明"赋值给"名字"盒子 
int 年龄 = 18;        // 把18赋值给"年龄"盒子 
bool 是否成年 = 年龄 >= 18; // 把比较结果(true)赋值给变量 

3. 复合赋值(简写操作)

运算符 含义 示例 等价于
+= 先加后赋 a += 5; a = a + 5;
-= 先减后赋 b -= 3; b = b - 3;
*= 先乘后赋 c *= 2; c = c * 2;
/= 先除后赋 d /= 4; d = d / 4;
%= 先取余后赋 e %= 2; e = e % 2;
实际例子
int 金币 = 50;
金币 += 10; // 金币 = 50 + 10 → 60 
金币 *= 2;  // 金币 = 60 * 2 → 120 
Console.WriteLine(金币); // 输出:120 

4. 自增/自减(++/--

运算符 作用 示例 结果(假设a=5
a++ 先用后加(后缀) int b = a++; b=5a=6
++a 先加后用(前缀) int b = ++a; b=6a=6
a-- 先用后减 int b = a--; b=5a=4
--a 先减后用 int b = --a; b=4a=4
关键区别
int x = 5;
int y = x++; // y拿到5,x变成6 
 
int m = 5;
int n = ++m; // n拿到6,m变成6 

5. 链式赋值(多个变量贴同一个标签)

int a, b, c;
a = b = c = 10; // 把a、b、c都赋值为10 

6. 特殊赋值运算符

运算符 作用 示例
??= 仅当变量为null时赋值 名字 ??= "无名";
?? 如果左边为null则用右边值 string 昵称 = 输入 ?? "默认";
实际应用
string 用户输入 = null;
string 显示名 = 用户输入 ?? "游客"; // 显示名="游客"
 
int? 可选分数 = null; // int?表示可空类型 
可选分数 ??= 60;     // 如果可选分数是null,则赋值为60 

7. 避坑指南

常见错误 问题 正确做法
===混淆 if (a = 5) ❌ if (a == 5) ✅
自增/自减顺序混淆 int b = a++ + a; ❌ 拆分成两步:int tmp = a++; b = tmp + a;
未初始化直接赋值 int a; a += 1; ❌ int a = 0; a += 1; ✅

总结口诀

🔹 等号=是贴标签,右边值往左边装
🔹 += *= 是简写,先算后赋要记详
🔹 a++ 先用后加++a 先加后用
🔹 ??= 专治null,链式赋值一行搞定

就像整理储物柜:
= → 往格子上贴物品标签
+= → 先往格子里加东西,再贴新标签
a++ → 先看格子里的东西,再悄悄+1

黄金法则

区分=(赋值)和==(比较)!
不确定自增顺序时,拆成两步写。
变量使用前务必初始化。

通俗解释:算术运算符 —— “计算器的基本功能”

1. 核心比喻

算术运算符就像计算器上的加减乘除按键,用来做数学计算。
在代码里,它们可以对数字(整数、小数)进行运算,并返回结果。

2. 五种基础运算符

运算符 名称 作用 示例 结果
+ 加法 两数相加 5 + 3 8
- 减法 两数相减 10 - 4 6
* 乘法 两数相乘 2 * 6 12
/ 除法 两数相除(整数/小数结果) 10 / 3 3(整数除法)
% 取余(模) 求两数相除的余数 10 % 3 1

3. 详细说明 & 示例

(1) 加法 + —— “合并”
int 苹果 = 5;
int 橘子 = 3;
int 水果总数 = 苹果 + 橘子; // 5 + 3 = 8 
Console.WriteLine(水果总数); // 输出:8 

适用场景:计数、金额累加。

(2) 减法 - —— “扣除”
int 钱包 = 100;
int 花费 = 45;
int 剩余 = 钱包 - 花费; // 100 - 45 = 55 

适用场景:计算余额、倒计时。

(3) 乘法 * —— “翻倍”
int 每小时工资 = 50;
int 工作小时 = 8;
int 总工资 = 每小时工资 * 工作小时; // 50 × 8 = 400 

适用场景:计算面积、总价。

(4) 除法 / —— “分配”

整数除法:直接取整(丢弃小数部分)。
小数除法:至少有一个操作数是小数时,结果保留小数。

int a = 10 / 3;    // 3(整数除法)
double b = 10 / 3.0; // 3.333...(小数除法)

避坑

int 错误 = 10 / 0; // ❌ 报错!除零异常(Runtime Error)
(5) 取余 % —— “剩下的”
int 余数 = 10 % 3; // 10 ÷ 3 = 3 余 1 → 余数是1 
bool 是偶数 = (数字 % 2 == 0); // 判断奇偶 

适用场景

判断能否整除(如轮播图循环)。
计算时间(如“75秒是1分15秒”)。

4. 算术表达式的计算顺序

优先级(从高到低):

() 括号优先
* / %
+ -

示例

int 结果 = 5 + 3 * 2; // 先算3×2=6,再5+6=11 
int 明确结果 = (5 + 3) * 2; // 先算5+3=8,再8×2=16 

5. 实际应用场景

(1) 游戏伤害计算
int 基础伤害 = 50;
int 暴击伤害 = 基础伤害 * 2; // 暴击翻倍 
int 最终伤害 = 暴击伤害 - 敌人防御;
(2) 分页计算
int 总数据 = 100;
int 每页显示 = 10;
int 总页数 = 总数据 / 每页显示; // 10页 
if (总数据 % 每页显示 != 0) 总页数++; // 有余数就加1页 
(3) 时间转换
int 总秒数 = 125;
int 分钟 = 总秒数 / 60; // 2分 
int 秒 = 总秒数 % 60;  // 5秒 
Console.WriteLine($"{分钟}分{秒}秒"); // 输出:2分5秒 

6. 避坑指南

常见错误 问题 正确做法
整数除法丢失小数 10 / 4 返回 2 用 10.0 / 4 或 (double)10 / 4
除零错误 int x = 5 / 0; ❌ 检查除数是否为0
混淆%/ /取余数 取余用%,取商用/

总结口诀

🔹 加减乘除取余,计算顺序括号先
🔹 整数除法会取整,要想精确转小数
🔹 %求余判奇偶,*翻倍/分摊
🔹 游戏伤害分页数,日常代码经常见

就像做小学数学题:
+ → 合并两个数
- → 从总数里扣除
* → 重复加多次(3×4=3+3+3+3)
/ → 均分(10个苹果分给3人,每人3个)
% → 分完剩下的(10÷3=3余1)

黄金法则

不确定优先级时加()
需要小数结果时,确保至少一个操作数是doublefloat
永远检查除数是否为0!

通俗解释:关系运算符 —— “比大小 & 判相等”

1. 核心比喻:身高PK & 找相同

关系运算符就像比较两个东西的大小或是否相同

比身高 → ><
测体重 → >=<=
找双胞胎 → ==!=

2. 6种关系运算符(返回truefalse

运算符 名称 作用 示例 结果
> 大于 左边是否大于右边 5 > 3 true
< 小于 左边是否小于右边 2 < 1 false
>= 大于等于 左边是否大于或等于右边 5 >= 5 true
<= 小于等于 左边是否小于或等于右边 4 <= 3 false
== 等于 两边是否值相等 3 == 3 true
!= 不等于 两边是否值不相等 4 != 4 false

3. 详细说明 & 示例

(1) 比大小 > < >= <=
int 小明年龄 = 18;
int 小红年龄 = 20;
 
bool 小明更大 = 小明年龄 > 小红年龄; // false 
bool 小红更大或同龄 = 小红年龄 >= 小明年龄; // true 
(2) 判相等 == !=
string 密码 = "123456";
string 输入 = "123456";
 
bool 密码正确 = 密码 == 输入; // true 
bool 密码错误 = 密码 != 输入; // false 

⚠️ 注意

=是赋值==才是比较!

int a = 5;  // 赋值(把5放进a)
bool b = (a == 5); // 比较(a是否等于5)

4. 实际应用场景

(1) 游戏关卡解锁
int 当前等级 = 10;
int 要求等级 = 15;
 
if (当前等级 >= 要求等级) 
{
    Console.WriteLine("关卡已解锁!");
}
else 
{
    Console.WriteLine("等级不足!");
}
(2) 用户登录验证
string 正确账号 = "admin";
string 输入账号 = Console.ReadLine(); // 用户输入 
 
if (输入账号 == 正确账号) 
{
    Console.WriteLine("登录成功!");
}
(3) 温度报警系统
float 当前温度 = 38.5f;
float 警戒温度 = 40.0f;
 
if (当前温度 >= 警戒温度) 
{
    触发报警();
}

5. 避坑指南

常见错误 问题 正确做法
混淆=== if (a = 5) ❌ if (a == 5) ✅
浮点数直接比较 0.1 + 0.2 == 0.3 ❌ 用差值判断:Math.Abs(a - b) < 0.0001
忽略大小写 "Hello" == "hello" ❌ Equals("hello", StringComparison.OrdinalIgnoreCase)

6. 特殊类型比较

(1) 字符串比较
string a = "abc";
string b = "ABC";
bool 相同1 = a == b; // false(区分大小写)
bool 相同2 = a.Equals(b, StringComparison.OrdinalIgnoreCase); // true(不区分大小写)
(2) 引用类型比较
class Person { public string Name; }
Person p1 = new Person() { Name = "Alice" };
Person p2 = new Person() { Name = "Alice" };
 
bool 值相同 = p1.Name == p2.Name; // true(比较字符串值)
bool 是同一对象 = p1 == p2;       // false(比较内存地址)

总结口诀

🔹 大于小于判高低,等于不等找相同
🔹 结果只有对或错,true/false记心中
🔹 赋值=和比较==,写错代码会发疯
🔹 字符串比大小写,浮点误差要宽容

就像考试评分:
>=60 → 及格
==100 → 满分
!=作弊 → 诚实

黄金法则

比较浮点数用误差范围,别直接用==
字符串比较注意大小写敏感。
引用类型比较默认比地址,不是比内容。

通俗解释:布尔逻辑运算符 —— “多重条件判断”

1. 核心比喻:开关组合

布尔逻辑运算符就像多个开关的组合控制

&&(与) → 必须所有开关都打开,灯才亮。
||(或) → 只要有一个开关打开,灯就亮。
!(非) → 反转开关状态(开变关,关变开)。

2. 三种基本逻辑运算符

运算符 名称 作用 示例 结果
&& 逻辑与 左右条件同时为真才返回true true && false false
|| 逻辑或 左右条件有一个为真就返回true true || false true
! 逻辑非 反转条件的布尔值 !true false

3. 详细说明 & 示例

(1) &&(与)—— “严格检查”
bool 有会员卡 = true;
bool 带身份证 = false;
 
bool 能办业务 = 有会员卡 && 带身份证; // false(缺身份证)

适用场景:需要同时满足多个条件(如登录验证)。

(2) ||(或)—— “宽松检查”
bool 有现金 = false;
bool 有信用卡 = true;
 
bool 能支付 = 有现金 || 有信用卡; // true(有信用卡即可)

适用场景:满足任一条件即可(如折扣资格检查)。

(3) !(非)—— “取反”
bool 是晴天 = false;
bool 要带伞 = !是晴天; // true(阴天带伞)

适用场景:反转条件逻辑(如“非工作日”)。

4. 实际应用场景

(1) 游戏关卡进入条件
int 玩家等级 = 25;
bool 完成任务 = true;
 
// 必须等级≥20且完成任务 
bool 能进关卡 = (玩家等级 >= 20) && 完成任务;
(2) 用户权限检查
bool 是管理员 = true;
bool 是VIP = false;
 
// 管理员或VIP可访问 
bool 能看高级内容 = 是管理员 || 是VIP;
(3) 否定条件简化
if (!string.IsNullOrEmpty(用户名)) 
{
    // 当用户名【不】为空时执行 
}

5. 短路计算(性能优化)

运算符 短路行为 示例
&& 左边为false时,右边不计算 false && 执行耗时函数()
|| 左边为true时,右边不计算 true || 执行耗时函数()
// 避免空引用异常 
if (用户 != null && 用户.年龄 > 18) 
{
    // 若用户为null,不会执行右边的检查 
}

6. 避坑指南

常见错误 问题 正确做法
混淆&&& &会计算所有条件 优先用&&||
过度嵌套 `if (a && (b
忽略短路特性 在右边写有副作用的代码 确保右边代码可被安全跳过

总结口诀

🔹 &&像串联电路,全真才通
🔹 ||像并联电路,一真就行
🔹 !是开关反转,真变假来假变真
🔹 短路计算能优化,条件顺序要当心

就像家里电路:
&& → 客厅灯和卧室灯打开,总闸才通电。
|| → 客厅灯卧室灯打开,走廊灯就亮。
! → 按下“总开关”,所有灯状态反转

黄金法则

多用&&||,少用&|(除非需要位运算)。
容易计算的条件放左边,利用短路提升性能。
复杂条件拆分成多行,避免嵌套地狱。

通俗解释:位运算符和位移运算符 —— “计算机的二进制魔法”

1. 核心比喻:开关与灯泡

二进制:计算机用 0(关)和 1(开)表示数据,就像一排灯泡。
位运算符:直接操作这些灯泡的开关状态。
位移运算符:把整排灯泡向左或向右移动。

2. 位运算符(逐位操作)

运算符 名称 作用 示例(二进制) 结果(二进制)
& 按位与 两个位都是1才得1 1100 & 1010 1000
| 按位或 两个位有一个1就得1 1100 | 1010 1110
^ 按位异或 两个位不同得1,相同得0 1100 ^ 1010 0110
~ 按位取反 反转所有位(0变1,1变0) ~1100(假设4位) 0011
实际代码示例(十进制)
int a = 12; // 二进制: 1100 
int b = 10; // 二进制: 1010 
 
Console.WriteLine(a & b); // 8  (1000)
Console.WriteLine(a | b); // 14 (1110)
Console.WriteLine(a ^ b); // 6  (0110)
Console.WriteLine(~a);    // -13(取决于int位数) 

3. 位移运算符(移动灯泡位置)

运算符 名称 作用 示例(二进制) 结果(二进制)
<< 左移 所有位向左移动,低位补0 1100 << 2 110000
>> 右移 所有位向右移动,高位补符号位 1100 >> 2 0011
实际代码示例(十进制)
int x = 12; // 二进制: 1100 
 
Console.WriteLine(x << 2); // 48 (110000,相当于×4)
Console.WriteLine(x >> 2); // 3  (0011,相当于÷4)
位移的数学意义

左移1位 ≈ 乘以2
右移1位 ≈ 除以2(向下取整)

4. 实际应用场景

(1) 游戏中的状态标记(用1个int存多个布尔值)
int 状态 = 0;
const int 隐身 = 1 << 0; // 0001 
const int 飞行 = 1 << 1; // 0010 
const int 无敌 = 1 << 2; // 0100 
 
// 开启飞行和无敌 
状态 |= (飞行 | 无敌); // 0010 | 0100 = 0110 
 
// 检查是否隐身 
bool 正在隐身 = (状态 & 隐身) != 0;
(2) 快速乘除2的幂次
int 快速乘以8 = 5 << 3; // 5×8=40 
int 快速除以4 = 20 >> 2; // 20÷4=5 
(3) 加密/哈希计算
int 哈希值 = 数据 ^ 密钥; // 异或用于简单加密 
(4) 颜色合成(ARGB)
int 红 = 0xFF0000;
int 透明度 = 0x80000000; // 50%透明度 
int 最终颜色 = 透明度 | 红;

5. 避坑指南

常见错误 问题 正确做法
混淆&&& &是位运算,&&是逻辑运算 逻辑判断用&&,位操作用&
忽略负数右移 -8 >> 1 得 -4(补1) 确保理解符号位扩展
位移位数超范围 x << 100 无意义 位移位数应 < 数据类型位数

总结口诀

🔹 位运算操作二进制,与或非来异或奇
🔹 左移乘二右移除,效率极高要注意
🔹 状态压缩位标记,一数多用真神奇
🔹 加密颜色游戏里,底层优化常见你

就像操控电灯面板:
& → 只有两个开关都打开,灯才亮
| → 任意一个开关打开,灯就亮
<< → 把所有灯向左挪动(最左的灯消失,右边补新灯)

黄金法则

位运算适合底层优化状态压缩
日常开发中优先用*/,除非明确需要性能优化。
处理负数时注意符号位扩展

通俗解释:特殊运算符 —— “代码里的快捷小技巧”

1. 核心比喻:程序员的高效工具包

特殊运算符就像快捷键,让代码更简洁、高效。
比如 ?.(避免空指针)、??(默认值)、?:(简化 if-else)。

2. 6种常见特殊运算符

运算符 名称 作用 示例 等价代码
?. 空条件运算符 安全访问成员(避免NullReferenceException user?.Name if (user != null) user.Name
?? 空合并运算符 提供默认值(若左边为null name ?? "匿名" name != null ? name : "匿名"
??= 空合并赋值 仅当变量为null时赋值 name ??= "默认" if (name == null) name = "默认"
?: 三元条件运算符 简化if-else age >= 18 ? "成年" : "未成年" if (age >= 18) "成年"; else "未成年";
=> Lambda表达式 简化匿名方法 numbers.Where(x => x > 5) delegate(int x) { return x > 5; }
nameof 名称获取 获取变量/类型的名称(避免硬编码) nameof(User.Name) "Name"

3. 详细说明 & 示例

(1) ?. —— “安全导航”
class User { public string Name; }
User user = null;
 
// 安全访问:如果user为null,不会抛异常,直接返回null 
string userName = user?.Name; // userName = null 
(2) ?? —— “兜底方案”
string 昵称 = null;
string 显示名 = 昵称 ?? "游客"; // 显示名 = "游客"
(3) ?: —— “简化if-else”
int 分数 = 75;
string 评级 = 分数 >= 60 ? "及格" : "不及格"; // 评级 = "及格"
(4) => —— “快速定义函数”
// Lambda表达式(匿名函数)
Func<int, int> 平方 = x => x * x;
Console.WriteLine(平方(5)); // 输出:25 
(5) nameof —— “防魔法字符串”
// Lambda表达式(匿名函数)
Func<int, int> 平方 = x => x * x;
Console.WriteLine(平方(5)); // 输出:25 

4. 实际应用场景

(1) 避免空指针异常
// 传统写法 
if (request != null && request.Body != null) 
{
    var data = request.Body.Data;
}
 
// 使用`?.`简化 
var data = request?.Body?.Data;
(2) 设置默认值
// 从配置读取,若为空则用默认值 
int 端口 = int.Parse(配置文件?.端口 ?? "8080");
(3) 简化条件判断
// 传统写法 
string 权限;
if (isAdmin) 权限 = "管理员";
else 权限 = "普通用户";
 
// 三元运算符简化 
string 权限 = isAdmin ? "管理员" : "普通用户";
(4) 快速筛选数据
List<int> 数字 = new List<int> { 1, 2, 3, 4, 5 };
var 大于3 = 数字.Where(x => x > 3); // [4, 5]

5. 避坑指南

常见错误 问题 正确做法
滥用?.链式调用 a?.b?.c?.d 可读性差 拆分成多行或提前判空
????=混淆 a ?? b不修改变量 需要赋值时用a ??= b
?:嵌套过深 a ? b : c ? d : e难懂 改用if-else或拆解逻辑

总结口诀

🔹 ?.问号点,安全访问防崩溃
🔹 ??双问号,空值兜底不狼狈
🔹 ?:三目符,简化判断真省事
🔹 =>箭头函,一行代码变简洁
🔹 nameof取名称,硬编码说再见

就像瑞士军刀:
?. → 安全剪刀(避免割伤)
?? → 备用小刀(默认工具)
?: → 迷你螺丝刀(快速解决小问题)

黄金法则

优先用?.代替多层if判空。
??适合配置读取和默认值场景。
复杂逻辑避免过度依赖三元运算符。

static unsafe void Main(string[] args)
{
    // * 取值,获取指针指向的变量的值  *a => 取a值
    // & 取地址,获取变量的地址  &a;
    // ?:条件表达式  1==1 ? "YES" : "NO"
    // is 类型判断符 
    // as  类型转换符
    //sizeof  取大小
    //typeof 取类型,返回类型的反射实例

    System.Int32 a = 99;//a是int ,a所指向的内存空间的大小就是4个字
    byte x = 99;//X所指向的内存空间的大小就是1个字
    byte[] y = new byte[444444]; 
    int* ptr = &a;
    Console.WriteLine(a);
    Console.WriteLine((int)ptr);
    Console.WriteLine(*ptr);
    var result = a > 99 ? "YES" : "NO";
    Console.WriteLine(result);
    if(a is int)
    {
        Console.WriteLine($"变量a是{a.GetType()}");
    }
    Object obj = "helloworld";

    string text = obj as string;
    Console.WriteLine(text);
    Console.WriteLine(typeof(int));
    Console.WriteLine(sizeof(int));
    Console.ReadKey();
}

通俗解释:顺序执行 —— “代码的流水线工作”

1. 核心比喻:做菜的步骤

顺序执行就像按食谱做菜,必须严格按步骤来:

洗菜 → 2. 切菜 → 3. 炒菜 → 4. 装盘
不能跳过任何一步,也不能打乱顺序,否则菜会做砸!

2. 顺序执行的特性

特点 说明 代码示例
自上而下 代码从第一行开始,一行一行执行 A(); B(); C();
不可跳跃 不会跳过中间的代码(除非报错) Console.WriteLine(1); Console.WriteLine(2);
依赖前一步结果 后一步操作可能需要前一步的数据 int x = 1; int y = x + 1;

3. 实际场景示例

(1) 用户注册流程
// 1. 输入用户名 
string 用户名 = Console.ReadLine();  
 
// 2. 输入密码  
string 密码 = Console.ReadLine();  
 
// 3. 保存到数据库  
数据库.保存用户(用户名, 密码);  
 
// 4. 发送欢迎邮件  
邮件系统.发送(用户名, "欢迎注册!");  

⚠️ 如果调换顺序

邮件系统.发送(用户名, "欢迎注册!");  // ❌ 报错!用户名还没获取!
string 用户名 = Console.ReadLine();  
(2) 游戏初始化
// 1. 加载地图 
地图.加载("森林");  
 
// 2. 加载角色  
角色.初始化("勇者");  
 
// 3. 播放背景音乐  
音频.播放("战斗BGM");  

4. 为什么顺序执行重要?

符合现实逻辑:就像必须先穿袜子再穿鞋,不能反过来。
避免空指针:如果先调用用户.姓名,再初始化用户,程序会崩溃。
调试方便:错误通常会出现在当前执行的代码行。

5. 避坑指南

常见错误 问题 正确做法
打乱代码顺序 先使用未初始化的变量 确保变量在使用前已赋值
忽略异常中断 报错后后续代码不执行 try-catch处理异常
过度嵌套 把顺序代码写成深层嵌套 拆分成多个步骤的平铺代码

总结口诀

🔹 代码像流水线,一行一行往下干
🔹 前因后果不能乱,先来后到是关键
🔹 变量未定别急用,否则程序就完蛋
🔹 顺序执行是基础,其他结构往上添

就像组装乐高:
步骤1:找齐所有零件(初始化变量)
步骤2:按说明书拼装(调用方法)
步骤3:最后贴贴纸(输出结果)

黄金法则

写代码时想象自己在做菜/组装玩具,必须有明确顺序。
遇到复杂逻辑时,先用注释写下步骤再写代码。
调试时从报错行往前找原因

通俗解释:if分支语句 —— “选择题的代码版”

1. 核心比喻:岔路口的选择

if 语句就像走到一个岔路口,根据条件决定走哪条路:

如果(if)晴天 → 走公园小路
否则如果(else if)阴天 → 带伞走大路
否则(else) → 直接回家

2. 三种基础结构

(1) 单if —— “只关心一种情况”
邮件系统.发送(用户名, "欢迎注册!");  // ❌ 报错!用户名还没获取!
string 用户名 = Console.ReadLine();  
(2) if-else —— “二选一”
邮件系统.发送(用户名, "欢迎注册!");  // ❌ 报错!用户名还没获取!
string 用户名 = Console.ReadLine();  
(3) if-else if-else —— “多选一”
邮件系统.发送(用户名, "欢迎注册!");  // ❌ 报错!用户名还没获取!
string 用户名 = Console.ReadLine();  

3. 实际应用场景

(1) 游戏技能冷却判断
邮件系统.发送(用户名, "欢迎注册!");  // ❌ 报错!用户名还没获取!
string 用户名 = Console.ReadLine();  
(2) 用户权限检查
邮件系统.发送(用户名, "欢迎注册!");  // ❌ 报错!用户名还没获取!
string 用户名 = Console.ReadLine();  
(3) 防呆设计(输入验证)
邮件系统.发送(用户名, "欢迎注册!");  // ❌ 报错!用户名还没获取!
string 用户名 = Console.ReadLine();  

4. 避坑指南

常见错误 问题 正确做法
条件重叠 if (x > 10) {...} else if (x > 5) 调整顺序或明确范围
漏写花括号 if (x>0) Console.Write("A"); Console.Write("B"); 始终使用{}包裹代码块
误用=代替== if (x = 5) ❌ if (x == 5) ✅

5. 特殊技巧

(1) 简化单行if
邮件系统.发送(用户名, "欢迎注册!");  // ❌ 报错!用户名还没获取!
string 用户名 = Console.ReadLine();  
(2) 直接返回布尔值
邮件系统.发送(用户名, "欢迎注册!");  // ❌ 报错!用户名还没获取!
string 用户名 = Console.ReadLine();  
(3) 早返模式(Early Return)
邮件系统.发送(用户名, "欢迎注册!");  // ❌ 报错!用户名还没获取!
string 用户名 = Console.ReadLine();  

总结口诀

🔹 if就像选择题,条件成立就走起
🔹 else if 是备选项,else 是兜底戏
🔹 条件顺序很重要,范围小的放前头
🔹 {} 包裹不能少,===要分清

就像考试判卷:
if (得分 >= 90) → 优秀
else if (得分 >= 60) → 及格
else → 不及格

黄金法则

最可能成立的条件放前面提高效率
嵌套不超过3层,否则改用switch或策略模式
永远用{}明确代码块范围,避免悬空else

通俗解释:switch语句 —— “智能分类器”

1. 核心比喻:自动分拣机

switch 就像一台智能分拣机,根据输入的值,自动跳转到对应的处理通道:

输入:一个变量(如数字、字符串)
分拣规则:匹配不同的 case(情况)
默认通道default(如果没有匹配的选项)

2. 基础语法(以成绩评级为例)

char 成绩 = 'B';
 
switch (成绩) 
{
    case 'A':
        Console.WriteLine("优秀!");
        break;
    case 'B':
        Console.WriteLine("良好!");
        break;
    case 'C':
        Console.WriteLine("及格");
        break;
    default:
        Console.WriteLine("无效成绩");
        break;
} 

3. 四大特点

特点 说明 示例
精确匹配 只执行匹配的case块(不像if会依次检查) case 1: 只匹配值为 1 的情况
必须break 每个case块结束时必须加break(否则编译报错) 漏写break会提示 Control cannot fall through...
支持多条件 多个case可以共享同一段代码(break穿透 case 1: case 2: Console.WriteLine("1或2"); break;
default可选 当没有匹配项时执行的默认逻辑(类似else default: Console.WriteLine("未知选项"); break;

4. 实际应用场景

(1) 游戏菜单选择
int 选项 = 2;
 
switch (选项) 
{
    case 1:
        开始新游戏();
        break;
    case 2:
        加载存档();
        break;
    case 3:
        退出游戏();
        break;
    default:
        Console.WriteLine("请输入1~3的数字!");
        break;
}
(2) 根据星期几执行任务
string 星期 = "周三";
 
switch (星期) 
{
    case "周一":
        开例会();
        break;
    case "周三":
    case "周五":
        健身(); // 周三和周五都执行健身 
        break;
    default:
        摸鱼();
        break;
}
(3) 枚举类型处理
enum 天气 { 晴, 雨, 雪 }
 
天气 今日天气 = 天气.雨;
 
switch (今日天气) 
{
    case 天气.晴:
        Console.WriteLine("出门晒太阳");
        break;
    case 天气.雨:
        Console.WriteLine("带伞");
        break;
    case 天气.雪:
        Console.WriteLine("穿羽绒服");
        break;
}

5. 常见错误

错误 问题 修复方式
漏写break 编译报错 每个case块末尾加break
case条件重复 同一值匹配多个case 合并相同逻辑的case
变量类型不匹配 switch(string)case 1: case类型必须和switch一致

6. 特殊技巧

(1) 返回值模式(C# 8.0+)
string 评价 = 成绩 switch 
{
    'A' => "优秀",
    'B' => "良好",
    _    => "再接再厉" // _ 表示默认值 
};
(2) 类型匹配(C# 7.0+)
switch (obj) 
{
    case int i when i > 0:
        Console.WriteLine($"正整数: {i}");
        break;
    case string s:
        Console.WriteLine($"字符串: {s}");
        break;
}

总结口诀

🔹 switch像分拣机,case对应各通道
🔹 break是刹车片,不写代码就撞车
🔹 多个选项可合并,default来兜底
🔹 枚举字符串常用它,if-else太啰嗦就用它

就像快递分拣:
case "北京" → 发往华北仓
case "上海" → 发往华东仓
default → 发往总部

黄金法则

超过3个条件时优先用switch(比if-else更清晰)
确保所有分支都有breakreturn
default处理意外值,避免静默失败

通俗解释:while循环 —— “重复干活的永动机”

1. 核心比喻:跑步机上的坚持

while 循环就像在跑步机上跑步:

只要(while)你还想跑 → 继续跑步
直到累得停下(条件不满足)→ 结束

2. 基础结构

while (条件) 
{
    // 重复执行的代码 
}

执行流程

检查条件是否为true
如果true → 执行代码块 → 返回第1步
如果false → 跳过循环

3. 实际场景

(1) 用户输入验证
string 密码;
while (密码 != "123456") 
{
    Console.Write("请输入密码:");
    密码 = Console.ReadLine();
}
Console.WriteLine("登录成功!");
(2) 游戏倒计时
int 倒计时 = 10;
while (倒计时 > 0) 
{
    Console.WriteLine($"还剩{倒计时}秒");
    倒计时--; // 别忘了更新条件变量!
}
Console.WriteLine("发射!");
(3) 批量处理数据
List<int> 待处理数据 = new List<int> { 1, 2, 3 };
int i = 0;
while (i < 待处理数据.Count) 
{
    Console.WriteLine(待处理数据[i] * 2);
    i++;
}

4. 避免死循环

危险示范
while (true) // 条件永远为true → 无限循环!
{
    Console.WriteLine("卡死在这里...");
}
正确做法

确保循环条件能被改变

bool 继续 = true;
while (继续) 
{
    // ...某些逻辑...
    继续 = false; // 通过某个条件退出 
}

5. vs for循环

对比项 while循环 for循环
适用场景 不确定循环次数(如等待用户输入) 明确知道循环次数(如遍历数组)
结构 只有条件判断 初始化+条件+迭代(for(int i=0; i<10; i++)

6. 特殊用法

(1) 模拟do-while

先执行一次再判断条件:

bool 首次执行 = true;
while (首次执行 || 条件) 
{
    首次执行 = false;
    // 业务代码 
}
(2) 嵌套循环
while (外层条件) 
{
    while (内层条件) 
    {
        // 复杂逻辑 
    }
}

总结口诀

🔹 while循环像跑步,条件为真就一直干
🔹 变量记得要更新,否则死循环卡成憨
🔹 次数不定首选它,for循环更爱数数字
🔹 嵌套可以但别深,三层以上头发昏

就像老妈催婚:
while (你还没结婚) → 继续安排相亲
你.结婚 = true; → 循环终止

黄金法则

确保循环条件有机会变false
超过5行的循环逻辑考虑抽成方法
优先选for如果能明确次数

通俗解释:do-while循环 —— “先上车后补票的循环”

1. 核心比喻:试用后决定

do-while 就像先体验再决定

不管怎样先执行一次(do)
然后检查条件(while)
如果条件满足,继续循环

和 while 的区别

while:先问再干(可能一次都不执行)
do-while先干再问(至少执行一次)

2. 基础语法

do 
{
    // 至少执行一次的代码 
} while (条件);

执行流程

执行代码块 → 2. 检查条件 → 3. 如果true,重复第1步

3. 实际场景

(1) 用户菜单交互
string 用户选择;
do 
{
    Console.WriteLine("1. 开始游戏");
    Console.WriteLine("2. 退出");
    Console.Write("请选择:");
    用户选择 = Console.ReadLine();
} while (用户选择 != "1" && 用户选择 != "2"); // 非法输入就重试 
(2) 游戏角色复活机制
bool 是否复活;
do 
{
    角色.复活();
    是否复活 = 检查金币是否足够(); // 复活后检查金币 
} while (!是否复活); // 金币不足就循环复活流程 
(3) 数据批量处理(至少处理一条)
int i = 0;
do 
{
    Console.WriteLine($"处理第{i+1}条数据");
    i++;
} while (i < 数据.Length);

4. 避坑指南

常见错误 问题 正确做法
漏写分号 } while (条件) ❌ } while (条件); ✅
条件永远为true 意外死循环 确保条件有机会变false
和while混淆 用while替代do-while 需要至少执行一次时用do-while

5. 特殊技巧

(1) 模拟其他语言中的repeat-until
bool 条件;
do 
{
    // 执行代码 
    条件 = 检查是否满足停止条件();
} while (!条件); // 直到条件满足时退出 
(2) 结合break提前退出
do 
{
    if (紧急情况) break; // 直接跳出循环 
} while (条件);

6. 总结口诀

🔹 do-while很特别,先斩后奏不纠结
🔹 至少执行第一次,条件检查在后面
🔹 菜单输入最常用,while的分号别忘写
🔹 死循环风险仍在,条件更新要保全

就像试用会员:
do → 先让你免费体验一个月
while → 到期后问你是否续费

黄金法则

必须至少执行一次时用do-while(如初始化逻辑)
优先用while如果可能一次都不执行
复杂条件考虑抽成方法保持可读性

通俗解释:for循环 —— “自动化的流水线工作”

1. 核心比喻:工厂装配线

for 循环就像一个全自动装配流水线

初始化:准备好工人和零件(设置初始值)
条件检查:检查是否还需要继续生产(循环条件)
迭代:每完成一个产品,工人休息一下(更新计数器)

2. 基础语法

for (初始化; 条件; 迭代) 
{
    // 循环体 
}

示例(打印1~5)

for (int i = 1; i <= 5; i++) 
{
    Console.WriteLine(i);
}

3. 实战:用for循环打印九九乘法表

(1) 单层循环(打印一行)
// 打印 3 的乘法行(3×1=3, 3×2=6,...)
int 基数 = 3;
for (int 乘数 = 1; 乘数 <= 9; 乘数++) 
{
    Console.Write($"{基数}×{乘数}={基数 * 乘数}	");
}

输出

3×1=3   3×2=6   3×3=9   ... 3×9=27 
(2) 双层循环(完整九九表)
for (int 基数 = 1; 基数 <= 9; 基数++)       // 外层控制行 
{
    for (int 乘数 = 1; 乘数 <= 基数; 乘数++) // 内层控制每行的列 
    {
        Console.Write($"{乘数}×{基数}={乘数 * 基数}	");
    }
    Console.WriteLine(); // 换行 
}

输出效果

1×1=1   
1×2=2   2×2=4   
1×3=3   2×3=6   3×3=9   
...  
1×9=9   2×9=18  ... 9×9=81 

4. 关键点解析

部分 作用 九九表示例
初始化 设置循环起点 int 基数 = 1(从1开始)
条件 决定是否继续循环 基数 <= 9(最多到9)
迭代 每次循环后的更新操作 基数++(每次+1)
嵌套循环 外层控制行,内层控制列 内层循环条件 乘数 <= 基数

5. 为什么用for循环?

优点 说明 对应九九表场景
紧凑 初始/条件/迭代写在一行,一目了然 清晰控制行和列的关系
避免死循环 迭代部分显式声明,比while更安全 基数++确保最终会退出循环
性能优化 编译器会对for循环做特殊优化 嵌套循环处理大量数据时效率高

6. 常见错误

错误 问题 修复方法
漏写迭代语句 死循环 for(int i=0; i<10; i++)
条件设置不当 少打或多打行 检查 基数 <= 9
嵌套循环变量同名 内层覆盖外层变量 改用不同变量名(如基数乘数

7. 变体技巧

(1) 倒序打印乘法表
for (int 基数 = 9; 基数 >= 1; 基数--) // 从9开始递减 
{
    for (int 乘数 = 1; 乘数 <= 基数; 乘数++) 
    {
        Console.Write($"{乘数}×{基数}={乘数 * 基数}	");
    }
    Console.WriteLine();
}
(2) 自定义格式对齐
for (int i = 1; i <= 9; i++) 
{
    for (int j = 1; j <= i; j++) 
    {
        Console.Write($"{j}×{i}={i*j,2}  "); // 占2位对齐 
    }
    Console.WriteLine();
}

总结口诀

🔹 for循环三板斧,初始化条件加迭代
🔹 外层行,内层列,九九乘法轻松解
🔹 先写框架再填肉,对齐格式用制表
🔹 变量作用要分明,嵌套循环莫重名

就像做菜:
初始化 → 备好食材(i=1
条件 → 检查是否做完9道菜(i<=9
迭代 → 每做完一道菜划掉菜单(i++

黄金法则

优先用for替代while如果循环次数明确
嵌套不超过3层,否则代码难维护
**善用Console.Write **保持对齐美观

通俗解释:foreach循环 —— “智能拆快递的机器人”

1. 核心比喻

foreach 就像自动拆快递的机器人

无需手动数包裹(不用写索引i++
自动识别每个物品(逐个取出数组/集合中的元素)
干完活自动停止(遍历完所有元素就退出)

2. 基础语法

foreach (数据类型 变量名 in 集合) 
{
    // 对每个元素的操作 
}
示例(遍历数组)
string[] 水果 = { "苹果", "香蕉", "橙子" };
 
foreach (string 单个水果 in 水果) 
{
    Console.WriteLine(单个水果);
}

输出

苹果  
香蕉  
橙子  

3. 三大特点

特点 说明 对比for循环
无需索引 自动获取元素,不用写i=0; i<长度; i++ 代码更简洁
只读安全 循环内不能修改集合(如增删元素) for可以修改集合
兼容性强 支持数组、ListDictionary 只能遍历索引结构的数据

4. 实际应用场景

(1) 遍历商品列表
List<string> 商品清单 = new List<string> { "手机", "耳机", "充电宝" };
 
foreach (var 商品 in 商品清单) 
{
    Console.WriteLine($"正在打包:{商品}");
}
(2) 统计考试成绩
int[] 分数 = { 85, 90, 78 };
int 总分 = 0;
 
foreach (int 单科分数 in 分数) 
{
    总分 += 单科分数;
}
Console.WriteLine($"平均分:{总分 / 分数.Length}");
(3) 处理字典数据
Dictionary<string, int> 库存 = new Dictionary<string, int>()
{
    {"苹果", 50},
    {"香蕉", 30}
};
 
foreach (var kvp in 库存) 
{
    Console.WriteLine($"{kvp.Key}还剩{kvp.Value}个");
}

5. 避坑指南

常见错误 问题 正确做法
试图修改集合 foreach内增删元素会报错 改用for循环或ToList()副本
混淆in关键字 写成=: 严格用in
忽略元素类型 var导致类型不明确 显式声明类型(如string

6. 性能优化技巧

(1) 对数组用foreachfor稍慢

数组:优先用for(直接索引访问更快)
集合类foreach更简洁(如ListDictionary

(2) 只读遍历时用foreach
// 推荐:不需要索引且不修改集合时 
foreach (var item in collection) { ... }

7. 特殊用法

(1) 自定义集合支持foreach

让类实现IEnumerable接口即可:

class 我的集合 : IEnumerable 
{
    public IEnumerator GetEnumerator() { ... }
}
 
// 使用 
foreach (var x in new 我的集合()) { ... }
(2) 并行遍历(PLINQ)
Parallel.ForEach(大数据集合, item => 
{
    // 多线程处理 
});

总结口诀

🔹 foreach像快递员,逐个送货不操心
🔹 数组集合都能用,字典KeyValue一把抓
🔹 只读遍历是本职,修改集合请换人
🔹 代码简洁效率高,没有索引更优雅

就像吃火锅:
for循环 → 自己用筷子夹菜(控制夹哪片肉)
foreach → 服务员帮你把菜涮好送到碗里(只管吃)

黄金法则

不需要索引时优先用foreach
遍历字典必用foreach(比for方便得多)
性能敏感场景对数组用for

通俗解释:break 和 continue —— “循环里的紧急按钮和跳过键”

1. 核心比喻

break 像紧急刹车:直接退出整个循环(不管后面还有没有代码)。
continue 像跳过广告:直接跳到下一次循环,当前这次循环剩下的代码不执行了。

2. break —— “立即停止循环”

(1) 作用

立刻终止整个循环forwhileforeachswitch)。
适用于找到目标就退出的场景。

(2) 示例(搜索数字)
for (int i = 1; i <= 9; i++) 
{
    for (int j = 1; j <= i; j++) 
    {
        Console.Write($"{j}×{i}={i*j,2}  "); // 占2位对齐 
    }
    Console.WriteLine();
}

3. continue —— “跳过本次循环,继续下一次”

(1) 作用

跳过当前这次循环,直接进入下一次循环(不会退出整个循环)。
适用于过滤不符合条件的数据

(2) 示例(打印偶数)
for (int i = 1; i <= 9; i++) 
{
    for (int j = 1; j <= i; j++) 
    {
        Console.Write($"{j}×{i}={i*j,2}  "); // 占2位对齐 
    }
    Console.WriteLine();
}

输出

2  
4  
6  
8  
10  

4. break vs continue

特点 break continue
用途 完全终止循环 跳过当前这次循环,继续下一次循环
适用场景 找到目标后退出 过滤数据,只处理符合条件的部分
效果 立刻终止整个循环体 只跳过当前这次,继续循环

5. 实际应用场景

(1) break 应用 —— 游戏血量检测
for (int i = 1; i <= 9; i++) 
{
    for (int j = 1; j <= i; j++) 
    {
        Console.Write($"{j}×{i}={i*j,2}  "); // 占2位对齐 
    }
    Console.WriteLine();
}
(2) continue 应用 —— 跳过空数据
for (int i = 1; i <= 9; i++) 
{
    for (int j = 1; j <= i; j++) 
    {
        Console.Write($"{j}×{i}={i*j,2}  "); // 占2位对齐 
    }
    Console.WriteLine();
}

输出

有效用户: 小明  
有效用户: 小红  
有效用户: 小刚  

6. 避坑指南

常见错误 问题 正确做法
switch里漏写break 会继续执行下一个case 每个case必须用breakreturn
continue用在switch switch不支持continue break或重构逻辑
嵌套循环用错break 只退出内层循环 如果需要退出多层循环,用goto或标志变量

7. 特殊技巧

(1) 用goto退出多层循环(谨慎使用)
for (int i = 1; i <= 9; i++) 
{
    for (int j = 1; j <= i; j++) 
    {
        Console.Write($"{j}×{i}={i*j,2}  "); // 占2位对齐 
    }
    Console.WriteLine();
}
(2) 用return直接结束方法
for (int i = 1; i <= 9; i++) 
{
    for (int j = 1; j <= i; j++) 
    {
        Console.Write($"{j}×{i}={i*j,2}  "); // 占2位对齐 
    }
    Console.WriteLine();
}

总结口诀

🔹 break是急刹车,整个循环都停下
🔹 continue跳广告,当前轮次不理它
🔹 switch里必break,嵌套循环小心抓瞎
🔹 一个退出一个跳,代码逻辑不抓瞎

就像看电视剧:
break → 直接关掉电视(不看了)
continue → 跳过片头曲(继续看正片)

黄金法则

**优先用breakcontinue**简化逻辑,但别滥用。
嵌套循环慎用break,可能需要goto或标志变量。
switch里必须用break,否则代码会“穿透”执行。

static unsafe void Main(string[] args)
{
    double[] scores = { 78,85,90,98,99,68,92};
    int index = 1;
    foreach (double score in scores)
    {
        if (score == 100)
        {
            break;
        }

        index++;
    }
    if (index <= scores.Length)
    {
        Console.WriteLine($"第{index}课是满分");
    }
    else
    {
        Console.WriteLine("没有满分");
    }

    for (int i = 0; i < 10; i++)
    {
        if (i % 2 == 0)
        {
            continue;
        }

        Console.WriteLine($"奇数:{i}");
    }

    Console.ReadKey();
}

通俗解释:goto —— “代码里的任意门”

1. 核心比喻:游戏里的传送卷轴

goto 就像游戏里的传送卷轴

直接跳转到指定位置(标签处)
无视代码的正常执行顺序(想跳就跳)

2. 基础语法

goto 标签名;
// ...其他代码...
标签名:
    // 要执行的代码 
示例(退出嵌套循环)
for (int i = 0; i < 3; i++) 
{
    for (int j = 0; j < 3; j++) 
    {
        if (i == 1 && j == 1) 
        {
            goto 退出所有循环; // 直接跳转到标签处 
        }
        Console.WriteLine($"i={i}, j={j}");
    }
}
 
退出所有循环:
Console.WriteLine("循环已跳出");

输出

i=0, j=0  
i=0, j=1  
i=0, j=2  
i=1, j=0  
循环已跳出  

3. 使用场景

场景 说明 示例
跳出多层嵌套循环 比用bool标志变量更直接 见上方示例
错误处理集中化 跳转到统一错误处理代码段 goto 错误处理;
旧代码兼容 维护历史遗留代码时可能遇到 早期代码常用goto

4. 为什么争议大?

优点

快速退出复杂逻辑(如嵌套循环)
简化某些特定场景的代码

缺点

破坏代码结构:让程序流程难以追踪
容易产生“面条代码”(Spaghetti Code)
现代编程中几乎被淘汰(可用函数/异常/标志变量替代)

5. 替代方案(比goto更优雅)

(1) 用函数替代
void 处理逻辑() 
{
    for (int i = 0; i < 3; i++) 
    {
        for (int j = 0; j < 3; j++) 
        {
            if (i == 1 && j == 1) return; // 直接退出函数 
            Console.WriteLine($"i={i}, j={j}");
        }
    }
}
(2) 用标志变量控制循环
bool 应该退出 = false;
for (int i = 0; i < 3 && !应该退出; i++) 
{
    for (int j = 0; j < 3 && !应该退出; j++) 
    {
        if (i == 1 && j == 1) 
        {
            应该退出 = true;
            break;
        }
        Console.WriteLine($"i={i}, j={j}");
    }
}
(3) 用异常处理(极端情况)
try 
{
    for (int i = 0; i < 3; i++) 
    {
        for (int j = 0; j < 3; j++) 
        {
            if (i == 1 && j == 1) throw new Exception("退出");
            Console.WriteLine($"i={i}, j={j}");
        }
    }
}
catch { /* 忽略异常 */ }

6. 唯一推荐使用场景

switch语句中跨case穿透(C#限制必须用goto):

switch (水果) 
{
    case "苹果":
    case "梨":
        Console.WriteLine("这是梨或苹果");
        goto case "香蕉"; // 跳转到香蕉的处理逻辑 
    case "香蕉":
        Console.WriteLine("处理香蕉");
        break;
}

总结口诀

🔹 goto像传送门,代码随便跳位置
🔹 争议大来风险高,滥用会成面条码
🔹 多层循环偶尔用,其他场景请三思
🔹 函数return更优雅,标志变量也推荐

就像哆啦A梦的任意门:
goto → 直接开门到目的地(但可能迷路)
函数调用 → 坐地铁按站下车(流程清晰)

黄金法则

99%的情况不要用goto,优先考虑重构代码。
唯一合理场景:退出深层嵌套循环或switch穿透。
代码审查见goto必问:是否真的无法用其他方式实现?

internal class Program
{        
    static unsafe void Main(string[] args)
    {
        /* 
         *  goto label;
                embedded-statement
            label:
                embedded-statement
         */

        int count = 1;
    login:
        Console.WriteLine("请输入密码:");
        string password = Console.ReadLine();
        if (password == "12345678")
        {
            Console.WriteLine("登录成功");
        }
        else
        {
            if(count++ > 3)
            {
                Console.WriteLine("密码错误次数过多,程序退出...");
            }
            else
            {
                Console.WriteLine("密码错误,请重试...");
                goto login;//转到login标签处
            }
        }

        Console.ReadKey();
    }

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容