4、C#语言基础(中):字符串操作、数组、集合、控制流语句

好,咱们接着聊。上一章我们把C#的变量、类型和运算符过了一遍,算是打了个地基。这一章,咱们要开始搭框架了——字符串、数组、集合,还有控制流。这些东西,说白了就是你每天写代码都要碰的。我做了十几年Windows桌面开发,可以负责任地告诉你:这部分学扎实了,后面写WPF、WinForms会顺手很多。

4.1 字符串操作:不只是拼接

字符串在C#里是个引用类型,但用起来像值类型。嗯,这里要注意:字符串是不可变的。你每次修改字符串,其实都是创建了一个新对象。我在项目中遇到过有人在一个循环里疯狂拼接字符串,结果界面卡死——后来换成StringBuilder,问题秒解。

4.1.1 常用方法

  • Length:获取字符串长度。比如 "你好".Length 返回2。
  • IndexOf / LastIndexOf:查找某个字符或子串的位置。找不到返回-1。
  • Substring:截取子串。记得参数是起始索引和长度。
  • Replace:替换。我经常用它来清理用户输入里的特殊字符。
  • Split:按分隔符拆分成数组。解析CSV文件时必备。
  • Trim / TrimStart / TrimEnd:去掉首尾空白。用户输入的数据,我建议一律先Trim一下。

重要提醒:字符串比较时,用 string.Equals(a, b, StringComparison.OrdinalIgnoreCase) 可以忽略大小写。别用 == 直接比,容易踩坑。

4.1.2 字符串拼接

拼接方式有好几种。我个人习惯用 $"Hello, {name}" 这种字符串插值,简洁又直观。如果是大量拼接,比如生成日志或构建SQL语句,一定要用 StringBuilder

// 推荐:字符串插值
string name = "张三";
string message = $"欢迎你,{name}!";

// 大量拼接时用 StringBuilder
var sb = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
    sb.Append($"第{i}行数据\n");
}
string result = sb.ToString();

小技巧:用 string.IsNullOrWhiteSpace() 判断字符串是否为空或全是空白,比手动判断更安全。

4.2 数组:固定大小的容器

数组是C#里最基础的数据结构。它的大小在创建时就固定了,不能动态增减。你想想看,这就像你买了一个固定格子的收纳盒——每个格子放一种类型的数据。

4.2.1 声明和初始化

// 声明一个int数组,长度为5
int[] numbers = new int[5];

// 声明并初始化
int[] scores = { 90, 85, 78, 92, 88 };

// 多维数组
int[,] matrix = new int[3, 3];

4.2.2 常用操作

  • Length:获取数组长度。一维数组用 arr.Length,多维数组用 arr.GetLength(0)
  • Array.Sort():排序。默认升序。
  • Array.Reverse():反转。
  • Array.IndexOf():查找元素索引。

避坑指南:我曾经在遍历数组时,不小心把索引写成了 i <= arr.Length,结果数组越界异常。记住:索引从0开始,最大索引是 Length - 1

4.3 集合:更灵活的容器

数组用起来有点死板,对吧?集合就灵活多了。C#里最常用的两个集合是 List<T>Dictionary<TKey, TValue>。它们都在 System.Collections.Generic 命名空间下。

4.3.1 List<T>:动态数组

List可以动态增减元素,内部其实是用数组实现的。当容量不够时,它会自动扩容——一般是翻倍。我在项目中遇到过频繁添加大量数据导致性能下降的情况,后来预先设置 Capacity 就好了。

// 创建List
List<string> names = new List<string>();

// 添加元素
names.Add("张三");
names.Add("李四");

// 插入
names.Insert(1, "王五");

// 删除
names.Remove("张三");   // 按值删除
names.RemoveAt(0);      // 按索引删除

// 查找
int index = names.IndexOf("李四");
bool exists = names.Contains("王五");

// 遍历
foreach (var name in names)
{
    Console.WriteLine(name);
}

4.3.2 Dictionary<TKey, TValue>:键值对

Dictionary是一种哈希表结构,查找速度极快——接近O(1)。我经常用它来做数据缓存或配置映射。比如把用户ID映射到用户对象。

// 创建Dictionary
Dictionary<int, string> students = new Dictionary<int, string>();

// 添加键值对
students.Add(1001, "张三");
students.Add(1002, "李四");

// 取值
string name = students[1001];  // 如果键不存在会抛异常

// 安全取值
if (students.TryGetValue(1003, out string result))
{
    Console.WriteLine(result);
}

// 遍历
foreach (var kvp in students)
{
    Console.WriteLine($"学号:{kvp.Key},姓名:{kvp.Value}");
}

重要提醒:Dictionary的键必须是唯一的,而且不能为null。取值时尽量用 TryGetValue,避免异常。

4.4 控制流语句:程序的指挥棒

控制流语句决定了代码的执行路径。说白了,就是让程序根据条件做不同的事,或者重复做某件事。

4.4.1 if-else 条件判断

这是最基础的条件语句。我个人习惯把最可能成立的条件放在最前面,这样能减少判断次数。

int score = 85;

if (score >= 90)
{
    Console.WriteLine("优秀");
}
else if (score >= 80)
{
    Console.WriteLine("良好");
}
else
{
    Console.WriteLine("继续努力");
}

4.4.2 switch 语句

当条件分支很多时,switch比if-else更清晰。C# 7.0之后,switch支持模式匹配,功能更强大了。

string day = "周一";

switch (day)
{
    case "周一":
    case "周二":
    case "周三":
    case "周四":
    case "周五":
        Console.WriteLine("工作日");
        break;
    case "周六":
    case "周日":
        Console.WriteLine("休息日");
        break;
    default:
        Console.WriteLine("无效输入");
        break;
}

小技巧:switch里多个case可以合并执行同一段代码,就像上面那样。另外,别忘了每个case后面加 break,否则会穿透。

4.4.3 for 循环

for循环适合已知循环次数的场景。比如遍历数组或List。

int[] numbers = { 10, 20, 30, 40, 50 };

for (int i = 0; i < numbers.Length; i++)
{
    Console.WriteLine(numbers[i]);
}

4.4.4 foreach 循环

foreach是C#里我最喜欢的循环方式。它不需要关心索引,直接遍历集合中的每个元素。代码简洁,也不容易出错。

List<string> fruits = new List<string> { "苹果", "香蕉", "橘子" };

foreach (string fruit in fruits)
{
    Console.WriteLine(fruit);
}

避坑指南:我曾经在foreach循环里尝试删除集合中的元素,结果抛出了 InvalidOperationException。记住:foreach遍历时不能修改集合。如果非要删除,用for循环倒着遍历。

4.4.5 while 循环

while循环适合条件不确定的场景。比如等待用户输入,或者读取文件直到结束。

int count = 0;
while (count < 5)
{
    Console.WriteLine($"当前计数:{count}");
    count++;
}

4.5 综合示例:学生成绩管理系统

咱们把今天学的知识串起来,写个小例子。这个例子模拟了一个简单的学生成绩管理。

// 用Dictionary存储学生信息:学号 -> 姓名
Dictionary<int, string> students = new Dictionary<int, string>();
students.Add(1001, "张三");
students.Add(1002, "李四");
students.Add(1003, "王五");

// 用List存储成绩
List<int> scores = new List<int> { 85, 92, 78 };

// 遍历输出
for (int i = 0; i < students.Count; i++)
{
    var student = students.ElementAt(i);
    Console.WriteLine($"学号:{student.Key},姓名:{student.Value},成绩:{scores[i]}");
}

// 计算平均分
int total = 0;
foreach (int score in scores)
{
    total += score;
}
double average = total / (double)scores.Count;
Console.WriteLine($"平均分:{average:F2}");

嗯,这一章的内容就这些。字符串、数组、集合、控制流——这些是C#编程的日常工具。你想想看,任何一个Windows桌面应用,都离不开这些基础操作。下一章我们会继续深入,聊聊方法、参数和面向对象编程。到时候见。