ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

C# 从集合、泛型、异常到 IO、多线程全套入门笔记

2026/8/3 9:48:04 拓冰建站 浏览量
C# 从集合、泛型、异常到 IO、多线程全套入门笔记 摘要本文整合 C# 基础进阶五大核心模块非泛型 / 泛型集合、泛型原理与约束、异常处理机制、文件 IO 流操作、进程与多线程同步配套完整可运行代码区分新旧容器优劣总结开发避坑点适合零基础入门、面试突击复习。 标签C#; .NET; 集合泛型多线程IO 流异常处理 分类后端开发 / C# 桌面开发前言初学 C# 时很容易混淆ArrayList和List、分不清栈 / 队列使用场景、写文件忘记释放资源、多线程并发出现数据错乱。本文结合课堂全套笔记把集合容器、泛型、异常、IO 文件、多线程五大高频知识点一次性梳理清楚所有案例均可直接复制运行同时标注生产环境推荐写法与淘汰 API。一、集合容器线性容器 键值容器1.1 非泛型容器System.Collections新项目不推荐1.1.1 ArrayList 动态数组本质是object[]可存任意类型存在装箱拆箱损耗无类型校验。核心特性容量自动扩容默认初始容量 16支持Add()尾部添加、Insert(index,obj)指定位置插入删除Clear()清空、Remove(元素)删首个匹配、RemoveAt(索引)、RemoveRange(起始,数量)查询Contains()判断存在、IndexOf()获取索引属性Count实际元素数 /Capacity总容量。示例代码csharp运行using System; using System.Collections; class TestArrayList { static void Main() { ArrayList arr new ArrayList(); arr.Add(10); arr.Add(测试字符串); arr.Add(true); arr.Insert(1, 999); // 索引1插入999 arr.Remove(测试字符串); // 删除指定元素 arr.RemoveAt(0); // 删除索引0 Console.WriteLine(arr.Contains(true)); // true // 遍历 foreach (var item in arr) { Console.WriteLine(item); } } }缺点混合类型存储取值强制转换极易报错性能差新项目一律用ListT替代。1.1.2 Queue 队列FIFO 先进先出场景消息队列、任务排队、打印队列。入队Enqueue(obj)出队取出并删除Dequeue()查看队首不删除Peek()统计Countcsharp运行Queue queue new Queue(); queue.Enqueue(消息1); queue.Enqueue(消息2); Console.WriteLine(queue.Peek()); // 消息1 Console.WriteLine(queue.Dequeue()); // 消息1队列仅剩消息21.1.3 Stack 栈LIFO 后进先出场景撤销操作、递归回溯、表达式求值。入栈Push(obj)出栈Pop()查看栈顶Peek()csharp运行Stack stack new Stack(); stack.Push(页面A); stack.Push(页面B); Console.WriteLine(stack.Pop()); // 页面B1.1.4 Hashtable 哈希键值对键唯一存储DictionaryEntry同样 object 装箱淘汰方案DictionaryTKey,TValuecsharp运行Hashtable ht new Hashtable(); ht.Add(id, 1001); ht[name] 张三; // 赋值键存在则覆盖 Console.WriteLine(ht.ContainsKey(id)); // 遍历键值对 foreach (DictionaryEntry kv in ht) { Console.WriteLine(${kv.Key}:{kv.Value}); }1.1.5 SortedList 自动排序键值容器自动按照 key 升序同时支持索引访问键访问双模式不允许重复 key。csharp运行SortedList sl new SortedList(); sl.Add(3, C); sl.Add(1, A); sl.Add(2, B); // 自动排序输出 1:A 2:B 3:C1.2 泛型容器System.Collections.Generic生产首选1.2.1 ListT 泛型动态数组替代 ArrayList强类型约束无装箱拆箱编译期类型检查方法与 ArrayList 完全对齐。csharp运行// 集合初始化器 Listint numList new Listint() { 1,2,3,4 }; numList.Add(5); numList.Insert(0,0); // 存储自定义实体 class Student { public int Id { get; set; } public string Name { get; set; } } ListStudent stus new ListStudent() { new Student{Id1001,Name小明} };1.2.2 DictionaryTKey,TValue 泛型字典替代 Hashtable核心优势O (1) 键查找推荐TryGetValue安全取值避免键不存在抛异常。csharp运行Dictionarystring,int ageDic new Dictionarystring,int(); ageDic[小明] 18; ageDic.Add(小红,17); // 安全取值推荐 if(ageDic.TryGetValue(小明,out int age)) { Console.WriteLine(age); } // 三种遍历 foreach(var kv in ageDic){} // 键值对 foreach(var k in ageDic.Keys){} // 仅键 foreach(var v in ageDic.Values){} // 仅值1.2.3 QueueT / StackT 泛型栈队列用法同非泛型仅增加类型约束杜绝类型混乱。csharp运行Queuestring msgQueue new Queuestring(); Stackint numStack new Stackint();1.3 容器选型对照表表格容器存储结构特性适用场景推荐度ArrayListobject 数组任意类型、装箱老旧维护项目❌淘汰ListTT 数组强类型、索引、扩容列表、批量数据✅首选QueueT循环数组FIFO 先进先出任务队列、消息✅常用StackT数组LIFO 后进先出撤销、递归✅常用Hashtable哈希表object 键值、装箱老旧项目❌淘汰Dictionary泛型哈希强类型、极速查键缓存、映射关系✅首选SortedList有序数组按键自动排序需要有序键值⭐按需使用二、泛型解决装箱拆箱与类型复用2.1 装箱 拆箱底层原理装箱值类型 → object 引用类型堆分配性能损耗拆箱object → 原始值类型强制转换csharp运行// 装箱 int a 10; object obj a; // 拆箱 int b (int)obj;非泛型容器存储值类型时会频繁装箱大量循环下性能断崖下跌泛型从根源解决该问题。2.2 泛型基础泛型方法 / 泛型类泛型将类型参数延迟到调用时指定编译器 JIT 会为每种 T 生成专属代码无装箱。泛型方法示例csharp运行// T为类型占位符 public static void ShowT(T data) { Console.WriteLine($数据{data}类型{typeof(T)}); } // 调用自动推导类型 Show(123); Show(测试文本); Show(DateTime.Now);泛型类示例csharp运行class MyContainerT { private T _data; public void Set(T val) _data val; public T Get() _data; } // 使用 MyContainerstring strBox new MyContainerstring(); strBox.Set(泛型测试);2.3 五大泛型约束 where通过where限制 T 的类型范围访问类型自有属性 / 方法where T : struct必须是值类型where T : class必须是引用类型where T : new()必须有无参公共构造函数放最后where T : 基类必须继承该类where T : 接口必须实现该接口csharp运行// 多重约束new()写末尾 public static void PrintUserT(T user) where T : People, ISay, new() { user.SayHi(); } class People { public int Id; } interface ISay { void SayHi(); }三、异常处理try-catch-finally 自定义异常3.1 常见系统异常IndexOutOfRangeException数组 / 集合下标越界NullReferenceException空对象调用成员DivideByZeroException除零错误IOException文件读写失败ArgumentException参数非法3.2 核心语法try-catch-finallytry存放可能报错代码catch捕获对应异常精准异常写在前Exception 兜底finally无论是否报错一定会执行用于释放资源文件、网络连接csharp运行static void ReadFileDemo() { FileStream fs null; try { fs new FileStream(test.txt, FileMode.Open); byte[] buf new byte[1024]; fs.Read(buf,0,buf.Length); } catch(FileNotFoundException ex) { Console.WriteLine(文件不存在ex.Message); } catch(Exception ex) { Console.WriteLine(未知错误ex); } finally { // 释放流资源 fs?.Close(); fs?.Dispose(); } }3.3 using 语法糖替代手动释放资源实现IDisposable接口的对象文件流、数据库连接可用using编译自动生成try-finally释放资源简化代码csharp运行// 等价上方finally释放逻辑 using(FileStream fs new FileStream(test.txt,FileMode.Open)) { byte[] buf new byte[1024]; fs.Read(buf,0,buf.Length); }3.4 throw 三种写法避坑throw ex;❌ 不推荐重置异常堆栈丢失原始报错行throw;✅ 推荐保留完整异常栈throw new Exception(提示,ex);✅ 包装异常形成异常链InnerExceptioncsharp运行try { int a 1 / 0; } catch(DivideByZeroException ex) { // 包装内部异常便于日志排查 throw new BusinessException(计算出错, ex); }3.5 自定义异常业务场景区分系统异常继承Exceptioncsharp运行public class BusinessException : Exception { public BusinessException(){} public BusinessException(string msg):base(msg){} public BusinessException(string msg,Exception inner):base(msg,inner){} } // 抛出自定义异常 throw new BusinessException(用户余额不足);四、IO 文件与流操作System.IO4.1 静态工具类Path / File / DirectoryPath路径处理不操作物理文件csharp运行string path C:\Desktop\demo.txt; Console.WriteLine(Path.GetFileName(path)); // demo.txt Console.WriteLine(Path.GetExtension(path)); // .txt Console.WriteLine(Path.GetDirectoryName(path)); // C:\Desktop Console.WriteLine(Path.Combine(C:\Desktop,a.txt)); // 拼接路径File文件静态读写小文件首选csharp运行// 一次性读取全部文本 string text File.ReadAllText(demo.txt,Encoding.UTF8); // 按行读取 string[] lines File.ReadAllLines(demo.txt); // 覆盖写入 File.WriteAllText(demo.txt,写入内容); // 追加写入 File.AppendAllText(demo.txt,追加文字); // 二进制读写图片、视频 byte[] data File.ReadAllBytes(1.jpg); File.WriteAllBytes(copy.jpg,data);Directory文件夹操作csharp运行Directory.CreateDirectory(C:\test); // 创建文件夹 Directory.Delete(C:\test,true); // true递归删除所有子文件 bool hasFolder Directory.Exists(C:\test);4.2 流分类Stream 抽象基类FileStream字节流读写任何文件图片 / 视频 / 文本StreamReader/StreamWriter字符流专门处理文本自带编码BufferedStream缓冲流提升大文件读写性能MemoryStream内存流无磁盘 IO文本读写示例StreamReader/StreamWritercsharp运行// 读取 using(StreamReader sr new StreamReader(demo.txt,Encoding.UTF8)) { while(!sr.EndOfStream) { string line sr.ReadLine(); } } // 写入第二个参数true追加 using(StreamWriter sw new StreamWriter(demo.txt,true,Encoding.UTF8)) { sw.WriteLine(新增一行); }五、进程与多线程同步System.Threading5.1 Process 进程类启动程序 / 查看进程csharp运行// 打开记事本 Process.Start(notepad); // 遍历所有进程关闭Edge foreach(var p in Process.GetProcesses()) { if(p.ProcessName.ToLower() msedge) { p.Kill(); } }5.2 Thread 基础线程主线程Main方法线程子线程用于耗时操作文件、网络、计算无参 / 有参线程创建csharp运行// 无参线程 Thread t1 new Thread(DoWork); t1.Start(); // 带object参数线程 Thread t2 new Thread(DoParamWork); t2.Start(传入参数); static void DoWork() { Console.WriteLine(子线程执行); } static void DoParamWork(object arg) { Console.WriteLine(arg.ToString()); }常用线程方法Start()启动线程Sleep(毫秒)当前线程休眠Join()阻塞主线程等待子线程执行完毕IsBackgroundtrue后台线程程序退出自动销毁5.3 线程同步锁 lock解决资源竞争多线程同时修改同一变量会出现数据错乱用 lock 锁定临界资源csharp运行class AppleDemo { static int appleCount 10; // 私有静态锁对象禁止string、this、typeof static readonly object locker new object(); static void Main() { Thread t1 new Thread(EatApple); Thread t2 new Thread(EatApple); t1.Start(张三); t2.Start(李四); } static void EatApple(string name) { while(true) { lock(locker) { if(appleCount 0) break; appleCount--; Console.WriteLine(${name}吃苹果剩余{appleCount}); Thread.Sleep(500); } } } }lock 避坑不要锁字符串、不要锁实例 this推荐私有静态只读 object。5.4 Mutex 跨进程互斥锁用于限制程序单开多个 exe 互斥csharp运行bool newMutex; Mutex mutex new Mutex(true,SingleApp,out newMutex); if(!newMutex) { Console.WriteLine(程序已启动直接退出); return; }六、全套知识点总结集合选型新项目全部使用泛型ListT、DictionaryTKey,TValue摒弃 ArrayList、Hashtable栈队列按需选用StackT/QueueT。泛型核心消除装箱拆箱编译类型安全where约束拓展泛型能力。异常规范分层捕获异常优先使用throw保留堆栈资源必须用using释放。IO 操作小文件用 File 静态方法大文件使用带缓冲流文本用 StreamReader多媒体用 FileStream 字节流。多线程规范共享资源必须加 lock 同步区分前后台线程避免死锁。七、面试高频问答ArrayList 和 ListT区别 答ArrayList 存储 object装箱拆箱、无类型校验ListT泛型强类型无性能损耗编译报错提前拦截。Dictionary 查找速度为什么快 答底层哈希表通过哈希码定位平均 O (1) 查询效率。using 的底层原理 答实现 IDisposable 接口编译生成 try-finally 块自动调用 Dispose 释放非托管资源。多线程不加锁会出现什么问题 答共享变量读写错乱、数据脏读业务逻辑结果不符合预期。