1:学习目标
- 掌握 C# 所有流程控制语句的用法
- 理解 C# 与 C++ 在流程控制上的关键差异
- 熟练掌握 C# 方法的定义与调用
- 深入理解
ref/out/in参数的高级用法 - 掌握方法重载、可选参数、命名参数等特性
- 学会使用本地函数简化代码
- 理解递归的原理和应用场景
- 所有知识点均与 C++ 对应概念进行深度对比
2:条件语句
C#的条件语句和C++基本相同,但是有一些重要的增强和限制。
1:if-else语句
if-else语句的语法行为和C++完全一致
cs
int score = 85;
if (score >= 90)
{
Console.WriteLine("优秀");
}
else if (score >= 80)
{
Console.WriteLine("良好");
}
else if (score >= 60)
{
Console.WriteLine("及格");
}
else
{
Console.WriteLine("不及格");
}
与C++的相同点:
- 条件表达式必须返回布尔值
- 支持嵌套 if-else
- 大括号可以省略(但强烈不推荐)
与C++的不同点:
C# 不允许将整数直接作为条件表达式,必须显式转换为 bool
cs
int x = 10;
// if (x) { } // 编译错误:无法将int转换为bool
if (x != 0) { } // 正确写法

2:switch语句
C# 的switch语句比 C++ 强大得多,支持更多的类型和模式匹配。
1:基本用法
cs
int day = 3;
switch (day)
{
case 1:
Console.WriteLine("星期一");
break;
case 2:
Console.WriteLine("星期二");
break;
case 3:
Console.WriteLine("星期三");
break;
case 4:
Console.WriteLine("星期四");
break;
case 5:
Console.WriteLine("星期五");
break;
case 6:
case 7:
Console.WriteLine("周末");
break;
default:
Console.WriteLine("无效的日期");
break;
}
与 C++ 的关键区别:
- 不允许隐式穿透 :每个 case 块必须以
break、return、throw或goto case结束,不能像 C++ 那样省略 break 导致自动穿透到下一个 case。 - 支持多个 case 标签共享同一个代码块:如上面的 case 6 和 case 7。
- 支持更多的类型:C# 的 switch 语句不仅支持整数类型,还支持字符串、枚举、char 等类型。
2:字符串switch
这是C#非常实用的特性,C++到了C++11才支持Switch可以用字符串
cs
string language = "C#";
switch (language)
{
case "C++":
Console.WriteLine("C++是一种高性能的系统编程语言");
break;
case "C#":
Console.WriteLine("C#是一种现代的通用编程语言");
break;
case "Java":
Console.WriteLine("Java是一种跨平台的编程语言");
break;
default:
Console.WriteLine("未知的编程语言");
break;
}
3:模式匹配(C#7.0+)
C#7.0引入了模式匹配,使switch语句更加强大
cs
object obj = "Hello World";
switch (obj)
{
case int i:
Console.WriteLine($"这是一个整数:{i}");
break;
case string s:
Console.WriteLine($"这是一个字符串:{s},长度为{s.Length}");
break;
case double d when d > 0:
Console.WriteLine($"这是一个正浮点数:{d}");
break;
case null:
Console.WriteLine("这是一个null值");
break;
default:
Console.WriteLine("这是一个未知类型");
break;
}
模式匹配可以根据对象的类型、值甚至条件来进行分支,这是 C++ 的 switch 语句完全不具备的功能。
3:循环语句
C#提供了4种循环语句:for,while,do-while和foreach,前三种和C++相同,foreach是C#特有的
1:for循环
for循环的语法和C++一样
cs
// 输出1到10
for (int i = 1; i <= 10; i++)
{
Console.WriteLine(i);
}
// 多个初始化和增量表达式
for (int i = 0, j = 10; i < j; i++, j--)
{
Console.WriteLine($"i={i}, j={j}");
}
2:while循环
while循环的语法和行为与 C++ 完全一致:
cs
int i = 1;
while (i <= 10)
{
Console.WriteLine(i);
i++;
}
3:do-while循环
do-while的语法行为和C++完全一致:
cs
int i = 1;
do
{
Console.WriteLine(i);
i++;
} while (i <= 10);
4:foreach循环
foreach循环是 C# 特有的,用于遍历集合或数组中的元素。它比传统的 for 循环更简洁、更安全。
cs
int[] numbers = { 1, 2, 3, 4, 5 };
foreach (int num in numbers)
{
Console.WriteLine(num);
}
// 遍历字符串中的每个字符
string message = "Hello C#";
foreach (char c in message)
{
Console.WriteLine(c);
}
与C++的范围for对比
cpp
int numbers[] = { 1, 2, 3, 4, 5 };
for (int num : numbers)
{
std::cout << num << std::endl;
}
关键区别:
-
C# 的
foreach循环可以遍历任何实现了IEnumerable接口的类型,而 C++ 的范围 for 循环需要类型提供begin()和end()方法。 -
C# 的
foreach循环是只读的,不能在循环体内修改集合元素:
cs
int[] numbers = { 1, 2, 3, 4, 5 };
foreach (int num in numbers)
{
// num = 10; // 编译错误:无法分配给foreach循环变量
}
cpp
for (int& num : numbers)
{
num = 10; // 正确
}
3.C# 的foreach循环不支持遍历过程中修改集合(添加或删除元素),否则会抛出InvalidOperationException异常。
4:跳转语句
1:break语句
break语句用于跳出最近的循环或 switch 语句,与 C++ 完全相同:
cs
for (int i = 1; i <= 10; i++)
{
if (i == 5)
{
break; // 跳出循环
}
Console.WriteLine(i);
}
// 输出:1 2 3 4
2:continue语句
continue语句用于跳过当前循环的剩余部分,进入下一次循环,与 C++ 完全相同:
cs
for (int i = 1; i <= 10; i++)
{
if (i % 2 == 0)
{
continue; // 跳过偶数
}
Console.WriteLine(i);
}
// 输出:1 3 5 7 9
3:goto语句
goto语句用于跳转到指定的标签位置。虽然很多人不推荐使用 goto,但在某些场景下(如跳出多层循环),goto 是最简洁的解决方案。(其实还是不怎么用)
cs
// 使用goto跳出多层循环
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (i == 1 && j == 1)
{
goto EndLoop; // 跳转到EndLoop标签
}
Console.WriteLine($"i={i}, j={j}");
}
}
EndLoop:
Console.WriteLine("循环结束");
与 C++ 的相同点:
- 语法和行为基本相同
- 不能跳转到方法外部
- 不能跳转到 try-catch 块内部
4:return语句
return语句用于从方法中返回,与 C++ 完全相同:
cs
int Add(int a, int b)
{
return a + b;
}
void PrintMessage(string message)
{
Console.WriteLine(message);
return; // 可以省略
}
5:方法系统(函数)
方法是 C# 中代码组织的基本单元,对应 C++ 中的函数。C# 的方法系统比 C++ 更强大,提供了更多的特性。
1:方法的定义与调用
方法的基本定义语法
cs
[访问修饰符] [返回类型] 方法名([参数列表])
{
// 方法体
[return 返回值;]
}
//void 可以不要返回值
cs
// 定义一个加法方法
public int Add(int a, int b)
{
return a + b;
}
// 调用方法
int result = Add(10, 20);
Console.WriteLine(result); // 输出 30
与 C++ 函数的对比:
- 语法基本相同
- C# 的方法必须定义在类或结构体内部,不能定义全局函数
- C# 的方法默认是
private访问修饰符,而 C++ 的函数默认是全局的
2:方法参数详解
C# 提供了四种参数传递方式:值参数、ref参数、out参数和in参数。
1:值参数
这是默认的参数传递方式,传递的是参数的副本。上一篇博客已经详细讲解过:
- 对于值类型:传递值的副本,方法内的修改不会影响原始变量
- 对于引用类型:传递引用的副本,方法内对对象内容的修改会影响原始对象,但对引用本身的修改不会影响原始引用
2:ref参数
ref参数传递的是变量的引用,方法内对参数的任何修改都会影响原始变量。
高级用法:ref 返回和 ref 局部变量(C# 7.0+)
C# 7.0 引入了 ref 返回和 ref 局部变量,允许方法返回引用,并将引用存储在局部变量中:
cs
internal class Program
{
public static ref int GetArrayElementRef(int[] array, int index)
{
return ref array[index];
}
static void Main(string[] args)
{
// 定义一个返回数组元素引用的方法
// 使用ref返回
int[] numbers = { 1, 2, 3, 4, 5 };
ref int element = ref GetArrayElementRef(numbers, 2);
element = 100; // 修改数组元素
Console.WriteLine(numbers[2]); // 输出 100
}
}
这个特性在处理大数组时可以显著提高性能,避免了复制整个数组元素。C++ 中可以通过返回指针或引用来实现类似的功能。
3:out参数
out参数用于从方法中返回多个值。与ref参数不同,out参数在传入方法时不需要初始化,方法必须为其赋值。
高级用法:元组返回(C# 7.0+)
虽然out参数可以返回多个值,但 C# 7.0 引入的元组是更优雅的解决方案:
cs
// 使用out参数返回多个值
public bool TryDivide(int dividend, int divisor, out int quotient, out int remainder)
{
if (divisor == 0)
{
quotient = 0;
remainder = 0;
return false;
}
quotient = dividend / divisor;
remainder = dividend % divisor;
return true;
}
// 使用元组返回多个值(推荐)
public (bool success, int quotient, int remainder) TryDivideTuple(int dividend, int divisor)
{
if (divisor == 0)
{
return (false, 0, 0);
}
return (true, dividend / divisor, dividend % divisor);
}
// 调用元组方法
var result = TryDivideTuple(10, 3);
if (result.success)
{
Console.WriteLine($"商:{result.quotient},余数:{result.remainder}");
}
// 解构元组
var (success, quotient, remainder) = TryDivideTuple(10, 3);
元组返回比out参数更简洁、更易读,是 C# 中返回多个值的首选方式。
4:in参数
in参数用于传递只读引用,方法内不能修改参数的值。in参数主要用于避免大值类型的复制开销,提高性能。
cs
// 定义一个大结构体
public struct LargeStruct
{
public long Value1;
public long Value2;
public long Value3;
public long Value4;
}
// 使用in参数传递,避免复制整个结构体
public void ProcessLargeStruct(in LargeStruct ls)
{
// ls.Value1 = 100; // 编译错误:不能修改in参数
Console.WriteLine(ls.Value1);
}
3:可选参数与命名参数
C# 4.0 引入了可选参数和命名参数,使方法调用更加灵活。
1:可选参数
可选参数在定义时指定默认值,调用时可以省略:
cs
// 定义带有可选参数的方法
public void PrintMessage(string message, int times = 1)
{
for (int i = 0; i < times; i++)
{
Console.WriteLine(message);
}
}
// 调用方法
PrintMessage("Hello"); // 使用默认值1
PrintMessage("Hello", 3); // 指定times为3
注意:
- 可选参数必须放在参数列表的最后
- 默认值必须是编译时常量
- 多个可选参数可以按顺序省略
2:命名参数
命名参数允许你通过参数名来指定参数值,而不需要按顺序:
cs
// 定义一个方法
public void CreateUser(string name, int age, string email = "", bool isActive = true)
{
Console.WriteLine($"Name: {name}, Age: {age}, Email: {email}, Active: {isActive}");
}
// 使用命名参数调用
CreateUser("张三", 25, isActive: false); // 只指定isActive参数,email使用默认值
CreateUser(age: 30, name: "李四"); // 不按顺序指定参数
命名参数在调用带有多个可选参数的方法时特别有用,可以提高代码的可读性。
4:方法重载
方法重载是指在同一个类中定义多个同名但参数列表不同的方法。C# 的方法重载规则与 C++ 基本相同:
cs
// 方法重载
public int Add(int a, int b)
{
return a + b;
}
public double Add(double a, double b)
{
return a + b;
}
public int Add(int a, int b, int c)
{
return a + b + c;
}
// 调用不同的重载方法
Console.WriteLine(Add(10, 20)); // 调用第一个Add
Console.WriteLine(Add(10.5, 20.5)); // 调用第二个Add
Console.WriteLine(Add(10, 20, 30)); // 调用第三个Add
与 C++ 的不同点:
C# 中ref和out可以作为重载的依据,而in不行:
cs
public void Method(int x) { }
public void Method(ref int x) { } // 合法重载
public void Method(out int x) { } // 合法重载
public void Method(in int x) { } // 编译错误:与第一个Method冲突
C# 不允许仅返回值不同的重载。
5:静态方法与实例方法
- 静态方法:属于类本身,不需要创建类的实例就可以调用
- 实例方法:属于类的实例,必须创建类的实例后才能调用
cs
public class Calculator
{
// 静态方法
public static int Add(int a, int b)
{
return a + b;
}
// 实例方法
public int Subtract(int a, int b)
{
return a - b;
}
}
// 调用静态方法
int sum = Calculator.Add(10, 20);
// 调用实例方法
Calculator calc = new Calculator();
int difference = calc.Subtract(20, 10);
这与 C++ 的静态成员函数和普通成员函数完全相同。
6:本地函数(C#7.0)
本地函数是定义在方法内部的函数,只能在包含它的方法内部调用。本地函数是 C# 特有的特性,C++ 没有直接对应的概念。
cs
public int CalculateFactorial(int n)
{
if (n < 0)
{
throw new ArgumentException("n不能为负数");
}
// 定义本地函数
int Factorial(int x)
{
if (x == 0)
{
return 1;
}
return x * Factorial(x - 1);
}
return Factorial(n);
}
// 调用方法
Console.WriteLine(CalculateFactorial(5)); // 输出 120
本地函数的优点:
- 封装性:只能在包含它的方法内部访问
- 可以访问包含方法的局部变量和参数
- 比 lambda 表达式更高效,支持递归
- 代码更清晰,将辅助函数与主函数放在一起
7:递归
递归是指方法调用自身的编程技巧。C# 的递归与 C++ 完全相同:
cs
// 计算斐波那契数列
public int Fibonacci(int n)
{
if (n <= 1)
{
return n;
}
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
// 调用
Console.WriteLine(Fibonacci(10)); // 输出 55
注意:
- 递归必须有终止条件,否则会导致栈溢出
- 递归深度过大会导致
StackOverflowException异常 - 对于深度较大的递归,建议使用迭代代替
6:总结
在这篇博客中,我们深入学习了 C# 的流程控制语句和方法系统。对于 C++ 开发者来说,大部分概念都是熟悉的,但 C# 提供了很多增强特性:
- switch 语句支持字符串和模式匹配
- foreach 循环提供了简洁安全的集合遍历方式
- 方法支持可选参数和命名参数
- 本地函数可以更好地封装辅助逻辑
- 元组返回提供了优雅的多值返回方式
这些特性可以显著提高代码的可读性和开发效率。