C# 泛型、文件、委托事件与多线程
一、思维导图
以下是本周学习内容的整体知识脉络:

二、思维导图详解
1. 泛型
泛型的核心思想是类型参数化——用占位符 <T> 代替具体类型,让类、方法、接口可以适配任意数据类型,同时保持编译时的类型安全。大大避免了传统 ArrayList 的装箱拆箱开销。常见泛型有 List<T>、Dictionary<TKey, TValue> 以及自定义泛型类/方法。
2. 文件操作
C# 操作文件主要有两类方式:
- File 静态类:
File.ReadAllText/File.WriteAllText一次性读写文本,简单直接,适合小文件。 - 文件流:
FileStream按字节流读写,StreamReader/StreamWriter按字符流读写,适合逐行处理大文件,自动处理编码。
选择原则:小文件用 File,大文件用流。
3. 委托
委托是 C# 中将方法作为数据类型传递的机制。从最早的手写 delegate 声明,到内置泛型委托 Func<T>(有返回值)、Action<T>(无返回值)、Predicate<T>(返回 bool),再到匿名方法和 Lambda 表达式,语法越来越简洁。委托是后面事件和 LINQ 的基础。
4. 事件
事件基于委托实现了发布-订阅模式。发布者通过 event 关键字声明事件,订阅者注册处理方法,事件触发时所有订阅者依次响应。标准做法是使用 EventHandler / EventHandler<TEventArgs> 委托。事件的核心价值在于解耦:发布者不需要知道谁来处理,订阅者可以随时增减。
5. 进程 (Process)
System.Diagnostics.Process 允许程序启动、监视、关闭外部进程:
Process.Start("notepad.exe"); // 启动记事本
Process.Start("https://example.com"); // 打开网页
通过 Process.Id、Process.ExitCode、Process.Kill() 等可以完整管理外部程序的生命周期。
6. 线程 (Thread)
线程是操作系统调度的最小单位,C# 通过 System.Threading.Thread 来管理:
- 前台线程:应用程序必须等所有前台线程结束后才退出。
- 后台线程 (IsBackground = true):应用程序退出时自动终止,不阻止进程关闭,常用于日志写入等非关键任务。
- Join():阻塞当前线程,等待目标线程执行完毕,实现线程间协调。
- Lock 锁:多线程同时访问共享资源时,
lock语句确保同一时刻只有一个线程进入临界区,解决线程安全问题。 - ThreadPool:复用线程,避免频繁创建销毁的开销,适合大量短任务。
三、最近遇到的问题与解题思路
问题:日志写入偶现"文件被占用"异常
用后台线程异步写日志,并在主线程退出前调用 Join 等待完成:
Thread logThread = new Thread(() =>
{
File.AppendAllText("log.txt", message);
});
logThread.IsBackground = true;
logThread.Start();
发现两种场景有问题:其一,日志线程没写完主线程就退出了(忘了 Join);其二,多个请求同时写同一个日志文件,抛出 IOException。
解题思路
-
后台线程 ≠ 随叫随停:即使设为
IsBackground = true,线程终止也是"突然死亡",中间恰好执行到写文件就会被截断。正确做法是在退出前logThread.Join()等待完成。 -
文件写入是共享资源:多个线程不能同时写同一个文件,在写文件外围加
lock:private static readonly object _fileLock = new object(); lock (_fileLock) { File.AppendAllText("log.txt", message); }这样同一时刻只有一个线程可以写入,彻底解决冲突。
关键认知:后台线程解决的是"不阻塞进程退出",Join 解决的是"确保任务完成",Lock 解决的是"多个线程不乱抢资源"。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)