3
社区成员
发帖
与我相关
我的任务
分享| 核心元素 | 定义 | 使用示例 | 适用场景 | 拓展知识点 |
| ? | 可空类型修饰符(Nullable<T>的语法糖),允许值类型存储null | csharp int? score = null; // 等价于 Nullable<int> score = null; bool? isSuccess = true; | 存储可能为空的数值(如数据库查询结果、可选参数值) | 1. 只能修饰值类型(int、DateTime等);2. 用.HasValue判断是否有值,.Value获取实际值;3. 可通过??赋值默认值 |
| ?. | 空条件运算符,避免null引用异常,左侧为null则表达式结果为null | csharp string userName = user?.Name; // user为null则返回null int? length = str?.Length; // str为null则返回null user?.SayHello(); // user为null则不执行方法 | 1. 访问可能为null的对象的属性/方法;2. 链式调用(如obj?.Prop1?.Prop2);3. 避免大量if (obj != null)判断 | 1. 右侧不能是赋值操作(如obj?.Name = "a" 报错);2. 结果类型为可空(值类型会转为Nullable<T>) |
| ?? | 空合并运算符,若左侧表达式不为null则返回左侧,否则返回右侧 | csharp int? num = null; int result = num ?? 0; // 0 string name = inputName ?? "匿名用户"; | 1. 为可空类型赋默认值;2. 避免null引用异常;3. 简化if-null判断 | 1. 左侧必须是可空类型(值类型?或引用类型);2. 右侧类型需与左侧兼容;3. 短路求值(左侧非null则不执行右侧) |
| => | lambda表达式运算符,用于简化匿名方法定义,分隔参数列表与表达式体 | csharp // 无参数 Func<string> getMsg = ()=>"Hello"; // 带参数 Func<int,int> square = x=>x*x; // 多语句 Action<int> print = x=>{ Console.WriteLine(x); }; | 1. LINQ查询(Where、Select等);2. 委托/事件快速赋值;3. 简化匿名方法代码 | 1. 单表达式可省略{}和return;2. 参数类型可省略(编译器自动推断);3. 与匿名方法本质一致,语法糖 |
| abstract | 抽象修饰符,可修饰类和方法,抽象类不能实例化,抽象方法无实现 | csharp abstract class Shape { public abstract double CalculateArea(); } class Circle : Shape { public double Radius { get; set; } public override double CalculateArea() => Math.PI * Radius * Radius; } | 定义基类契约(如形状、交通工具),子类必须实现抽象方法,强制多态 | 1. 抽象类可包含抽象方法和非抽象方法;2. 抽象方法必须在抽象类中;3. 子类必须实现所有抽象方法(否则子类也需为抽象类) |
| Action<> | 泛型委托(System.Action),用于封装无返回值的方法,参数个数0-16个,无返回值类型参数 | ```csharp // 无参数,无返回值 Action printHello = () => Console.WriteLine("Hello World"); // 1个参数,无返回值(打印整数) Action<int> printNumber = x => Console.WriteLine($"数字:{x}"); // 2个参数,无返回值(打印两个字符串) Action<string, string> printNames = (a, b) => Console.WriteLine($"{a} 和 {b}"); // 调用 printHello(); printNumber(100); printNames("张三", "李四"); ``` | 1. 无返回值的回调函数(如任务完成后的通知);2. 批量数据处理(遍历集合执行操作);3. 简化自定义无返回值委托的定义;4. 事件订阅(无参数事件) | 1. 无参数无返回值:Action;2. 有参数无返回值:Action<T1, T2, ..., Tn>;3. 不能用于有返回值的方法(有返回值用Func<>);4. 与Func<>互补,覆盖大部分委托场景 |
| as | 类型转换运算符,将对象转换为指定类型,转换失败返回null(不抛出异常) | csharp object obj = "Hello"; string str = obj as string; // 转换成功,str="Hello" int num = obj as int; // 转换失败,num=null if (str != null) { Console.WriteLine(str.Length); } | 1. 安全的类型转换(避免InvalidCastException);2. 引用类型和可空值类型的转换;3. 简化类型转换逻辑 | 1. 转换失败返回null(不能用于非可空值类型);2. 仅支持引用类型和可空值类型的转换;3. 比强制转换更安全,比is+强制转换更简洁;4. 转换过程中不执行用户定义的转换(仅支持隐式转换和显式转换) |
| Assembly | 程序集类(System.Reflection.Assembly),封装了.NET程序集(exe或dll)的元数据,用于在运行时加载程序集、获取程序集中的类型信息 | ```csharp // 1. 获取当前执行程序集 Assembly currentAssembly = Assembly.GetExecutingAssembly(); Console.WriteLine("当前程序集:" + currentAssembly.FullName); // 2. 获取调用当前方法的程序集 Assembly callingAssembly = Assembly.GetCallingAssembly(); // 3. 加载外部程序集(通过路径) Assembly externalAssembly = Assembly.LoadFrom(@"D:\Test\MyLibrary.dll"); // 4. 获取程序集中的所有类型 Type[] types = externalAssembly.GetTypes(); foreach (var type in types) { Console.WriteLine("程序集中的类型:" + type.FullName); } // 5. 通过程序集创建类型实例 Type userType = externalAssembly.GetType("MyLibrary.User"); object userInstance = Activator.CreateInstance(userType); ``` | 1. 插件系统开发(动态加载外部插件dll);2. 运行时扩展程序功能(加载额外程序集);3. 程序集元数据查看(如版本信息、包含的类型);4. 跨程序集反射操作 | 1. 常用加载方法:LoadFrom()(通过文件路径)、Load()(通过程序集名称)、GetExecutingAssembly()(当前执行程序集);2. 程序集是.NET的部署单元,包含IL代码和元数据;3. 可通过Assembly获取程序集的版本、文化信息、引用的其他程序集等;4. 加载的程序集常驻内存,除非卸载整个应用域(.NET Core/.NET 5+中应用域已废弃,需使用AssemblyLoadContext) |
| async/await | 异步编程关键字组合,async标记方法为异步,await等待异步操作完成 | csharp async Task DownloadFileAsync(string url) { using (var client = new HttpClient()) { var bytes = await client.GetByteArrayAsync(url); await File.WriteAllBytesAsync("file.txt", bytes); } } | 1. UI程序异步操作(避免界面卡死);2. 多异步任务并行执行;3. 提高程序吞吐量 | 1. async方法返回类型只能是Task、Task<T>或void(仅事件处理用);2. await不能在同步方法中使用;3. 异步方法不会自动开启新线程 |
| Async/Await(补充细节) | 异步编程关键字(C# 5.0+),基于任务并行库(TPL),通过async标记异步方法,await标记需要等待的异步操作,实现非阻塞异步编程,简化异步代码逻辑 | ```csharp // 1. 基本异步方法(返回Task) public async Task DownloadFileAsync(string url, string savePath) { using (var httpClient = new HttpClient()) { // 等待异步下载操作(非阻塞,释放线程) byte[] data = await httpClient.GetByteArrayAsync(url); // 等待异步写入文件 await File.WriteAllBytesAsync(savePath, data); Console.WriteLine("文件下载完成"); } } // 2. 异步方法返回值(Task<TResult>) public async Task<int> CalculateSumAsync(int a, int b) { // 模拟耗时操作(Task.Delay是异步等待) await Task.Delay(1000); return a + b; } // 3. 异步方法调用(await必须在async方法中) public async Task RunAsyncOperations() { // 调用异步方法并等待结果 await DownloadFileAsync("https://example.com/file", "localfile.txt"); int sum = await CalculateSumAsync(10, 20); Console.WriteLine($"Sum: {sum}"); // 并行执行多个异步操作(Task.WhenAll) Task<int> task1 = CalculateSumAsync(1, 2); Task<int> task2 = CalculateSumAsync(3, 4); int[] results = await Task.WhenAll(task1, task2); Console.WriteLine($"Results: {results[0]}, {results[1]}"); // 异步流(C# 8.0+,IAsyncEnumerable<T>) await foreach (var item in GetAsyncDataAsync()) { Console.WriteLine($"异步流数据:{item}"); } } // 4. 异步流(返回IAsyncEnumerable<T>) public async IAsyncEnumerable<int> GetAsyncDataAsync() { for (int i = 0; i < 5; i++) { await Task.Delay(500); yield return i; } } // 5. 入口方法调用(.NET 6+控制台程序支持async Main) async Task Main() { await RunAsyncOperations(); } ``` | 1. I/O密集型操作(文件读写、网络请求、数据库操作);2. 避免UI界面冻结(如WinForm、WPF异步操作);3. 并行执行多个异步任务(提高效率);4. 异步流处理(如实时数据推送、大文件分片读取) | 1. 核心原理:async标记的方法会被编译为状态机,await标记的位置是状态切换点;2. 异步方法返回类型:Task(无返回值)、Task<TResult>(有返回值)、void(仅用于异步事件处理程序,不推荐)、IAsyncEnumerable<T>(异步流);3. 等待模式:await会释放当前线程,待异步操作完成后恢复执行,实现非阻塞;4. 异常处理:异步方法中的异常会被捕获并存储在Task中,需通过await或Task.Wait()获取;5. 避免异步死锁:在UI线程或ASP.NET请求线程中,避免使用Task.Wait()、Task.Result等阻塞操作(推荐使用await);6. 异步流需配合await foreach遍历 |
| Attribute | 特性(System.Attribute),是一种特殊的类,用于为代码元素(类、方法、属性等)添加元数据,元数据可通过反射在运行时获取 | ```csharp // 自定义特性(继承Attribute) [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public class DescriptionAttribute : Attribute { public string Info { get; } public int Version { get; set; } public DescriptionAttribute(string info) { Info = info; } } // 使用自定义特性 [Description("用户实体类", Version = 1)] public class User { [Description("用户ID")] public int Id { get; set; } [Description("获取用户信息")] public string GetInfo() => $"用户ID:{Id}"; } // 通过反射获取特性信息 Type userType = typeof(User); var classAttr = (DescriptionAttribute)Attribute.GetCustomAttribute(userType, typeof(DescriptionAttribute)); Console.WriteLine(classAttr.Info); // 用户实体类 Console.WriteLine(classAttr.Version); // 1 var methodAttr = (DescriptionAttribute)Attribute.GetCustomAttribute(userType.GetMethod("GetInfo"), typeof(DescriptionAttribute)); Console.WriteLine(methodAttr.Info); // 获取用户信息 ``` | 1. 为代码元素添加描述信息(如接口文档、字段说明);2. 运行时通过反射获取元数据(如序列化配置、权限控制);3. 代码生成(如ORM框架映射、API文档生成);4. 标记特殊功能(如[Serializable]序列化、[Obsolete]过时警告) | 1. 自定义特性必须继承Attribute类,类名建议以Attribute结尾(使用时可省略);2. [AttributeUsage]特性用于限制自定义特性的适用目标(类、方法、属性等);3. 特性参数分为位置参数(构造函数参数)和命名参数(属性赋值);4. 特性本身不影响代码执行,需通过反射获取并处理元数据才会生效 |
| Attribute(特性) | 特性(System.Attribute),是一种元数据,用于为代码元素(类、方法、属性、参数等)添加额外信息,这些信息可在运行时通过反射获取,实现对代码的标记和配置 | ```csharp // 1. 定义自定义特性(继承Attribute) [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = false)] public class MyCustomAttribute : Attribute { public string Description { get; } public int Version { get; set; } // 特性构造函数(参数为必选配置) public MyCustomAttribute(string description) { Description = description; } } // 2. 使用自定义特性标记代码元素 [MyCustom(description: "用户服务类", Version = 1)] [MyCustom(description: "核心业务类", Version = 2)] // AllowMultiple=true支持多个特性 public class UserService { [MyCustom(description: "获取用户信息方法")] public string GetUserInfo(int userId) { return $"用户{userId}的信息"; } } // 3. 运行时通过反射获取特性信息 Type userServiceType = typeof(UserService); // 获取类上的特性 object[] classAttributes = userServiceType.GetCustomAttributes(typeof(MyCustomAttribute), inherit: false); foreach (MyCustomAttribute attr in classAttributes) { Console.WriteLine($"类特性 - 描述:{attr.Description},版本:{attr.Version}"); } // 获取方法上的特性 MethodInfo getInfoMethod = userServiceType.GetMethod("GetUserInfo"); object[] methodAttributes = getInfoMethod.GetCustomAttributes(typeof(MyCustomAttribute), inherit: false); foreach (MyCustomAttribute attr in methodAttributes) { Console.WriteLine($"方法特性 - 描述:{attr.Description},版本:{attr.Version}"); } // 4. 使用内置特性 // [Obsolete]:标记方法已过时 public class OldClass { [Obsolete("此方法已过时,请使用NewMethod替代", true)] // true表示调用时编译错误 public void OldMethod() { Console.WriteLine("旧方法"); } public void NewMethod() { Console.WriteLine("新方法"); } } // OldClass oldObj = new OldClass(); // oldObj.OldMethod(); // 编译错误:此方法已过时 // [Serializable]:标记类可序列化 [Serializable] public class Person { public string Name { get; set; } public int Age { get; set; } } ``` | 1. 代码标记(如标记过时方法、可序列化类);2. 运行时配置(通过反射获取特性信息实现动态逻辑);3. 框架开发(如ASP.NET Core中的[Route]、[HttpGet]等特性);4. 代码生成(根据特性信息自动生成代码);5. 权限控制、日志记录等AOP场景(通过特性标记需要增强的代码元素) | 1. 核心概念:特性是元数据,不直接影响代码执行,需通过反射读取并处理;2. 自定义特性:必须继承Attribute类,类名建议以Attribute结尾(使用时可省略);3. AttributeUsage特性:用于配置自定义特性的适用目标(AttributeTargets)、是否允许多个(AllowMultiple)、是否可继承(Inherited);4. 内置特性:[Obsolete](标记过时)、[Serializable](标记可序列化)、[Conditional](条件编译)、[DisplayName](显示名称)等;5. 反射获取:通过Type、MethodInfo等反射类的GetCustomAttributes()方法获取特性实例;6. 限制:特性构造函数的参数只能是常量表达式、typeof表达式或数组;7. 常用框架特性:ASP.NET Core中的路由特性、依赖注入特性;EF Core中的实体映射特性([Key]、[Column]等) |
| bool | 布尔值类型(System.Boolean),仅存储true(真)或false(假),占1字节 | csharp bool isLogin = true; bool hasPermission = user.Role == Role.Admin; if (isLogin) { /* 执行逻辑 */ } | 条件判断(if/while循环)、状态标记(是否登录、操作是否成功) | 1. 默认值为false;2. 不能直接与int转换(需显式判断,如bool flag = (num == 1));3. 可空布尔值为bool? |
| break | 中断语句关键字,用于退出当前循环(for/while/foreach)或switch语句 | csharp for (int i = 0; i < 10; i++) { if (i == 5) break; // 退出for循环 Console.WriteLine(i); } switch (num) { case 1: break; // 退出switch } | 提前终止循环(如找到目标值后退出)、避免switch语句穿透 | 1. 仅退出当前所在循环/switch;2. 多层循环需配合标签或flag使用;3. 与return区别:不退出方法 |
| byte | 8位无符号值类型(System.Byte),范围0~255,存储二进制数据或小整数 | csharp byte flag = 0x01; // 十六进制表示 byte[] buffer = new byte[1024]; // 存储二进制数据 bool isPositive = byte.MaxValue == 255; | 1. 二进制数据处理(文件流、网络传输);2. 存储0~255范围的无符号整数;3. 节省内存(比int占用少) | 1. 默认值为0;2. 可显式转换为int(无需担心溢出);3. 与sbyte(有符号字节)范围互补;4. 常用于位图、音频等二进制格式处理 |
| Caller Info Attributes | 调用方信息特性(System.Runtime.CompilerServices),包括CallerFilePath、CallerLineNumber、CallerMemberName,用于在方法中获取调用方的文件路径、行号、成员名称,无需调用方显式传递 | ```csharp using System.Runtime.CompilerServices; // 定义带有调用方信息特性的方法 public static void Log( string message, [CallerFilePath] string filePath = "", // 调用方文件路径 [CallerLineNumber] int lineNumber = 0, // 调用方行号 [CallerMemberName] string memberName = "") // 调用方成员名称 { Console.WriteLine($"【日志】{message}"); Console.WriteLine($"调用方文件:{filePath}"); Console.WriteLine($"调用方行号:{lineNumber}"); Console.WriteLine($"调用方成员:{memberName}"); Console.WriteLine("------------------------"); } // 调用Log方法(无需传递调用方信息参数) public class TestClass { public void TestMethod() { Log("TestMethod执行中"); // 行号假设为25 } public static void Main() { Log("程序启动"); // 行号假设为30 TestClass test = new TestClass(); test.TestMethod(); } } // 输出示例(实际路径和行号根据项目而定): // 【日志】程序启动 // 调用方文件:D:\Projects\Test\Program.cs // 调用方行号:30 // 调用方成员:Main // ------------------------ // 【日志】TestMethod执行中 // 调用方文件:D:\Projects\Test\Program.cs // 调用方行号:25 // 调用方成员:TestMethod // ------------------------ // 配合属性使用(自动获取属性名) private string _name; public string Name { get => _name; set { _name = value; Log($"属性{memberName}已更新为:{value}"); // memberName自动为"Name" } } ``` | 1. 日志记录(自动记录日志调用位置);2. 调试信息收集(定位问题代码位置);3. 属性变更通知(自动获取变更的属性名);4. 框架开发(如MVVM框架的属性通知、AOP框架的调用信息收集) | 1. 核心特性:调用方信息由编译器在编译时注入,无需运行时计算,性能无损耗;2. 适用参数:必须是可选参数(指定默认值),否则编译器无法注入;3. 特性说明:CallerFilePath(完整文件路径)、CallerLineNumber(调用代码行号)、CallerMemberName(调用方成员名称,如方法名、属性名、构造函数名);4. 扩展:可自定义调用方信息特性(继承Attribute,标记[AttributeUsage(AttributeTargets.Parameter)]);5. 限制:仅在编译时注入,若调用方是动态生成的代码(如反射、动态方法),可能无法正确获取信息;6. 命名空间:System.Runtime.CompilerServices,需添加对应using语句 |
| CancellationToken/CancellationTokenSource | 任务取消机制核心类(System.Threading.CancellationTokenSource/CancellationToken),CancellationTokenSource用于发出取消信号,CancellationToken用于接收取消信号,实现任务的可控取消 | ```csharp // 1. 基本取消示例 CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken token = cts.Token; // 启动可取消任务 Task task = Task.Run(() => { try { for (int i = 0; i < 10; i++) { // 检查是否收到取消信号(两种方式) token.ThrowIfCancellationRequested(); // 直接抛出异常 // if (token.IsCancellationRequested) break; Console.WriteLine($"任务执行中:{i}"); Thread.Sleep(500); } } catch (OperationCanceledException ex) { Console.WriteLine($"任务被取消:{ex.Message}"); } }, token); // 主线程延迟后发出取消信号 Thread.Sleep(2000); cts.Cancel(); // 发出取消信号 task.Wait(); cts.Dispose(); // 释放资源 // 2. 取消多个任务(共享CancellationToken) CancellationTokenSource cts2 = new CancellationTokenSource(); CancellationToken token2 = cts2.Token; Task taskA = Task.Run(() => RunTask("TaskA", token2), token2); Task taskB = Task.Run(() => RunTask("TaskB", token2), token2); Thread.Sleep(1500); cts2.Cancel(); // 同时取消taskA和taskB Task.WaitAll(taskA, taskB); cts2.Dispose(); // 辅助方法 void RunTask(string taskName, CancellationToken token) { try { for (int i = 0; i < 10; i++) { token.ThrowIfCancellationRequested(); Console.WriteLine($"{taskName}执行中:{i}"); Thread.Sleep(500); } } catch (OperationCanceledException) { Console.WriteLine($"{taskName}被取消"); } } // 3. 延迟取消 CancellationTokenSource cts3 = new CancellationTokenSource(3000); // 3秒后自动取消 Task task3 = Task.Run(() => RunTask("Task3", cts3.Token), cts3.Token); task3.Wait(); cts3.Dispose(); ``` | 1. 可取消的异步/并行任务(如长时间运行的任务、循环任务);2. 超时控制(通过延迟取消实现任务超时);3. 批量任务统一取消(共享取消令牌);4. 用户触发的任务取消(如UI界面的“取消”按钮);5. 资源清理(任务取消后的资源释放) | 1. 核心关系:CancellationTokenSource是取消信号的发送者,CancellationToken是信号的接收者(可传递给多个任务);2. 取消方式:主动调用Cancel()(立即取消)、CancelAfter(int millisecondsDelay)(延迟取消);3. 任务接收取消信号的方式:检查IsCancellationRequested属性、调用ThrowIfCancellationRequested()方法(抛出OperationCanceledException);4. 资源释放:CancellationTokenSource实现了IDisposable接口,使用后需调用Dispose()释放资源;5. 不可变性:CancellationToken一旦被标记为取消,状态不可更改;6. 空令牌:CancellationToken.None表示空令牌(不会触发取消),用于默认参数 |
| case/default | switch语句的分支标签:case匹配指定值,default处理未匹配的所有情况 | csharp string fruit = "苹果"; switch (fruit) { case "苹果": Console.WriteLine("红色"); break; case "香蕉": Console.WriteLine("黄色"); break; default: Console.WriteLine("未知颜色"); break; } | switch语句的分支定义,覆盖所有可能的表达式值 | 1. case标签值必须唯一;2. default可放在任意位置(建议最后);3. C# 8.0+支持switch表达式(更简洁) |
| char | 16位Unicode字符类型(System.Char),存储单个字符,范围\u0000~\uffff | csharp char ch1 = 'A'; char ch2 = '\u0041'; // 同'A' bool isDigit = char.IsDigit('5'); | 存储单个字符(字母、数字、符号)、字符处理(字符串拆分、验证) | 1. 用单引号包裹;2. 支持转义字符(\n换行、\t制表符);3. 可隐式转换为ushort,显式转换为int |
| checked | 溢出检查关键字,强制对数值运算进行溢出检测,溢出时抛出OverflowException | csharp int max = int.MaxValue; try { int result = checked(max + 1); // 抛出溢出异常 } catch (OverflowException ex) { Console.WriteLine(ex.Message); } checked { int a = 2147483647; int b = a + 1; // 溢出抛出异常 } | 1. 关键数值计算(如金融、计数),确保数据准确性;2. 需严格检测溢出的场景;3. 调试阶段定位溢出问题 | 1. 与unchecked(禁用溢出检查)相对;2. 可用于语句块或表达式;3. 仅对值类型的算术运算和转换有效;4. 默认情况下,Debug模式启用溢出检查,Release模式禁用 |
| class | 引用类型类,面向对象编程的核心,封装数据和行为,存储在堆上 | csharp class Person { public string Name { get; set; } public int Age { get; set; } public void SayHello() => Console.WriteLine($"你好,{Name}"); } Person person = new(){ Name="李四", Age=30 }; | 复杂业务实体(用户、订单、商品)、需要继承和多态的场景 | 1. 支持继承(单继承)和接口实现;2. 默认有无参构造函数;3. 赋值为引用传递(多个变量指向同一实例) |
| ConcurrentBag<T> | 并发安全的无序集合(System.Collections.Concurrent.ConcurrentBag<T>),属于并发集合,专为多线程场景设计,支持线程安全的添加、删除、遍历操作,基于线程本地存储(TLS)优化性能 | ```csharp // 1. 初始化ConcurrentBag<T> ConcurrentBag<int> concurrentBag = new ConcurrentBag<int>(); // 2. 多线程添加元素 Parallel.For(0, 10, i => { concurrentBag.Add(i); Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}添加元素:{i}"); }); Console.WriteLine($"ConcurrentBag元素个数:{concurrentBag.Count}"); // 10 // 3. 多线程获取并删除元素(TryTake:从集合中获取并移除一个元素) Parallel.For(0, 10, _ => { if (concurrentBag.TryTake(out int value)) { Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}获取元素:{value}"); } }); Console.WriteLine($"TryTake后元素个数:{concurrentBag.Count}"); // 0 // 4. 尝试获取元素但不删除(TryPeek:仅获取,不移除) concurrentBag.Add(100); concurrentBag.Add(200); if (concurrentBag.TryPeek(out int peekValue)) { Console.WriteLine($"TryPeek获取的元素:{peekValue}"); // 100或200(无序) Console.WriteLine($"TryPeek后元素个数:{concurrentBag.Count}"); // 2 } // 5. 遍历ConcurrentBag<T>(线程安全) Console.WriteLine("遍历ConcurrentBag元素:"); foreach (int value in concurrentBag) { Console.WriteLine(value); // 100,200(顺序不保证) } // 6. 自定义类型的并发集合 ConcurrentBag<Person> personBag = new ConcurrentBag<Person>(); Parallel.Invoke( () => personBag.Add(new Person { Name = "张三", Age = 28 }), () => personBag.Add(new Person { Name = "李四", Age = 22 }), () => personBag.Add(new Person { Name = "王五", Age = 30 }) ); foreach (var p in personBag) { Console.WriteLine(p); // 无序输出三个Person对象 } // 7. 转换为非并发集合 List<int> list = concurrentBag.ToList(); Console.WriteLine($"转换为List后的元素:{string.Join(",", list)}"); ``` | 1. 多线程数据共享场景(如多线程生产-消费模型);2. 并发任务的结果收集(如多线程计算后的结果存储);3. 线程安全的临时数据存储;4. 无需排序的并发数据处理场景 | 1. 核心特性:线程安全、无序、支持并发添加/删除/遍历,基于线程本地存储(TLS)优化性能(线程优先访问自己添加的元素,减少锁竞争);2. 并发集合家族:属于System.Collections.Concurrent命名空间,同家族还有ConcurrentQueue<T>(并发队列)、ConcurrentStack<T>(并发栈)、ConcurrentDictionary<TKey,TValue>(并发字典);3. 关键方法:Add()(添加元素)、TryTake()(获取并移除元素)、TryPeek()(获取元素不移除)、Count(元素个数);4. 遍历:遍历过程中集合可被修改(线程安全),但不保证遍历到所有元素(若遍历过程中有元素被添加/移除);5. 性能:在多线程添加/获取元素场景下,性能优于非并发集合(如List<T>)加锁;6. 与List<T>的区别:List<T>非线程安全,ConcurrentBag<T>线程安全;List<T>有序,ConcurrentBag<T>无序;7. 适用场景:适合多线程生产-消费模型,无需保证元素顺序的场景;若需要有序,可使用ConcurrentQueue<T>(FIFO)或ConcurrentStack<T>(LIFO) |
| ConcurrentDictionary<,> | 线程安全的泛型字典(System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>),实现IDictionary<,>,专为多线程并发访问设计,提供原子操作 | ```csharp // 初始化线程安全字典 var concurrentDict = new ConcurrentDictionary<string, string>(); // 原子添加(不存在则添加,返回是否成功) bool added = concurrentDict.TryAdd("key1", "value1"); // 原子获取或添加(不存在则通过委托生成值) string value2 = concurrentDict.GetOrAdd("key2", k => $"生成的值:{k}"); // 原子更新(根据旧值更新新值) concurrentDict.TryUpdate("key1", "newValue1", "value1"); // 多线程并发操作 Parallel.For(0, 1000, i => { string key = $"key{i}"; concurrentDict.TryAdd(key, $"value{i}"); }); Console.WriteLine(concurrentDict.Count); // 1000(无并发问题) ``` | 1. 多线程环境下的键值对存储(如多线程缓存、共享配置);2. 并发添加、删除、更新键值对的场景;3. 避免手动加锁的线程安全字典需求;4. 高并发数据处理中的临时数据存储 | 1. 提供多种原子操作:TryAdd、TryGetValue、TryUpdate、GetOrAdd、AddOrUpdate等;2. 性能优于“lock+普通Dictionary”(优化了并发访问逻辑);3. 不支持直接通过索引赋值(需用原子方法);4. 属于System.Collections.Concurrent命名空间,需引用对应程序集 |
| ConcurrentDictionary<TKey, TValue> | 并发安全的字典(System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue>),专为多线程场景设计的键值对集合,支持线程安全的添加、删除、查找、更新操作,基于分段锁优化并发性能 | ```csharp // 1. 初始化ConcurrentDictionary<TKey, TValue> ConcurrentDictionary<int, string> concurrentDict = new ConcurrentDictionary<int, string>(); // 2. 多线程添加元素(TryAdd:添加键值对,键不存在时成功) Parallel.For(0, 5, i => { bool isAdded = concurrentDict.TryAdd(i, $"值{i}"); Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}添加键{i}:{isAdded}"); }); Console.WriteLine($"ConcurrentDictionary元素个数:{concurrentDict.Count}"); // 5 // 3. 多线程获取元素(TryGetValue:获取指定键的值) Parallel.For(0, 5, i => { if (concurrentDict.TryGetValue(i, out string value)) { Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}获取键{i}的值:{value}"); } }); // 4. 多线程更新元素(多种更新方式) // 方式1:TryUpdate(键存在且当前值匹配时更新) bool isUpdated1 = concurrentDict.TryUpdate(0, "更新后的值0", "值0"); Console.WriteLine($"更新键0:{isUpdated1}"); // True // 方式2:AddOrUpdate(键不存在则添加,存在则更新) string addOrUpdateValue = concurrentDict.AddOrUpdate( key: 5, addValueFactory: k => $"新增值{k}", // 键不存在时执行 updateValueFactory: (k, v) => $"更新值{k}" // 键存在时执行 ); Console.WriteLine($"AddOrUpdate键5的结果:{addOrUpdateValue}"); // 新增值5 // 方式3:GetOrAdd(键不存在则添加,存在则获取) string getOrAddValue = concurrentDict.GetOrAdd( key: 6, valueFactory: k => $"新增值{k}" ); Console.WriteLine($"GetOrAdd键6的结果:{getOrAddValue}"); // 新增值6 // 5. 多线程删除元素(TryRemove:删除指定键的键值对) Parallel.For(0, 7, i => { if (concurrentDict.TryRemove(i, out string removedValue)) { Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}删除键{i}的值:{removedValue}"); } }); Console.WriteLine($"删除后元素个数:{concurrentDict.Count}"); // 0 // 6. 遍历ConcurrentDictionary<TKey, TValue>(线程安全) concurrentDict.Add(10, "值10"); concurrentDict.Add(20, "值20"); Console.WriteLine("遍历ConcurrentDictionary:"); foreach (var kvp in concurrentDict) { Console.WriteLine($"键:{kvp.Key},值:{kvp.Value}"); } // 7. 自定义比较器 ConcurrentDictionary<string, int> caseInsensitiveDict = new ConcurrentDictionary<string, int>(StringComparer.OrdinalIgnoreCase); caseInsensitiveDict.TryAdd("Apple", 1); if (caseInsensitiveDict.TryGetValue("apple", out int count)) { Console.WriteLine($"忽略大小写获取键apple的值:{count}"); // 1 } ``` | 1. 多线程键值对存储场景(如多线程缓存、多线程配置存储);2. 并发数据共享的键值映射(如多线程任务的状态跟踪);3. 高并发读写的字典场景(避免普通Dictionary加锁的性能瓶颈);4. 分布式任务的结果缓存(多线程计算结果的键值存储) | 1. 底层优化:基于分段锁(将字典分为多个段,每个段独立加锁),支持多个线程同时访问不同段,大幅提升并发性能;2. 核心方法:TryAdd()、TryGetValue()、TryUpdate()、TryRemove()、AddOrUpdate()、GetOrAdd();3. 与Dictionary<TKey,TValue>的区别:Dictionary非线程安全,ConcurrentDictionary线程安全;Dictionary在并发读写时需手动加锁,ConcurrentDictionary内置线程安全机制;4. 原子操作:AddOrUpdate()和GetOrAdd()是原子操作,避免多线程竞争导致的逻辑错误;5. 性能:在高并发场景下,性能远优于普通Dictionary加锁(lock);6. 遍历:遍历过程中字典可被修改(线程安全),但不保证遍历到所有元素(若遍历过程中有元素被添加/删除);7. 自定义比较器:支持自定义键的比较规则(如忽略大小写的字符串键),通过构造函数传入IEqualityComparer<TKey> |
| Conditional Attribute(条件特性) | 条件特性(System.Diagnostics.ConditionalAttribute),内置特性,用于标记方法,使方法的调用仅在指定的预处理符号被定义时才会被编译和执行,否则调用会被忽略,常用于调试日志等场景 | ```csharp using System.Diagnostics; // 1. 定义带条件特性的方法(调试日志) public static class DebugHelper { // 仅当定义了DEBUG预处理符号时,调用才有效 [Conditional("DEBUG")] public static void DebugLog(string message) { Console.WriteLine($"【DEBUG】{DateTime.Now:HH:mm:ss} - {message}"); } // 仅当定义了RELEASE预处理符号时,调用才有效 [Conditional("RELEASE")] public static void ReleaseLog(string message) { Console.WriteLine($"【RELEASE】{DateTime.Now:HH:mm:ss} - {message}"); } // 多个条件:定义了DEBUG或TRACE时均有效 [Conditional("DEBUG"), Conditional("TRACE")] public static void TraceLog(string message) { Console.WriteLine($"【TRACE】{DateTime.Now:HH:mm:ss} - {message}"); } } // 2. 调用条件方法 public class Program { public static void Main() { DebugHelper.DebugLog("程序启动(调试模式)"); DebugHelper.ReleaseLog("程序启动(发布模式)"); DebugHelper.TraceLog("程序启动(跟踪模式)"); // 条件方法的参数仍会被计算(即使方法调用被忽略) int value = 10; DebugHelper.DebugLog($"计算结果:{value * 2}"); // 即使DEBUG未定义,value*2仍会计算 // 解决参数计算问题:使用lambda延迟计算 DebugHelper.DebugLogLazy(() => $"计算结果:{value * 2}"); } } // 优化:延迟计算参数的条件方法 public static class DebugHelper { [Conditional("DEBUG")] public static void DebugLogLazy(Func<string> messageFactory) { if (messageFactory != null) { DebugLog(messageFactory()); } } } // 3. 定义预处理符号(项目属性中配置,或代码文件顶部) #define DEBUG // 定义DEBUG符号(仅当前文件有效) // #define RELEASE // 定义RELEASE符号 ``` | 1. 调试日志输出(仅调试模式输出日志,发布模式忽略);2. 条件性执行代码(如调试模式执行额外校验,发布模式跳过);3. 多环境适配(不同环境执行不同逻辑);4. 性能优化(发布模式忽略无需执行的调试逻辑) | 1. 工作原理:编译器根据预处理符号是否定义,决定是否保留条件方法的调用代码;2. 预处理符号:可在项目属性(生成→条件编译符号)中定义,或通过#define指令在代码文件顶部定义;3. 多个条件:一个方法可标记多个Conditional特性,只要任意一个符号被定义,方法调用就会保留;4. 注意事项:条件方法的参数会被正常计算(即使方法调用被忽略),若参数计算耗时,需使用lambda等方式延迟计算;5. 方法限制:条件方法必须是static void(无返回值),不能是接口方法、抽象方法;6. 与#if的区别:#if是编译时完全排除代码块,Conditional是仅排除方法调用,方法定义仍存在;7. 常用符号:DEBUG(调试模式默认定义)、RELEASE(发布模式默认定义)、TRACE(跟踪模式) |
| const | 常量修饰符,用于声明编译时常量(值类型或string),必须在声明时初始化 | csharp public const int MaxCount = 100; public const string DefaultName = "匿名用户"; const double Pi = 3.1415926; | 1. 存储固定不变的常量(如数学常数、配置常量);2. 提高代码可读性(替代魔法数字);3. 编译时确定值的场景 | 1. 只能修饰值类型(int、double等)和string,不能修饰引用类型;2. 必须在声明时初始化(值为编译时常量);3. 访问时无需实例化类(静态访问);4. 与readonly的区别:const是编译时常量(值嵌入代码),readonly是运行时常量(值在运行时确定) |
| continue | 继续语句关键字,用于跳过当前循环剩余代码,直接进入下一次循环迭代 | csharp for (int i = 0; i < 10; i++) { if (i % 2 == 0) continue; // 跳过偶数 Console.WriteLine(i); // 仅输出奇数 } | 过滤循环中的特定元素、跳过异常/无效数据的处理逻辑 | 1. 不退出循环,仅跳过当前迭代;2. 多层循环中仅影响当前所在循环;3. 与break区别:break终止循环,continue跳过当前迭代 |
| DateTime | 值类型(System.DateTime),用于表示日期和时间,范围从0001年1月1日到9999年12月31日,精度为100纳秒 | ```csharp // 获取当前日期时间 DateTime now = DateTime.Now; // 本地时间 DateTime utcNow = DateTime.UtcNow; // UTC时间(世界协调时间) DateTime today = DateTime.Today; // 本地时间,时间部分为00:00:00 // 构造DateTime DateTime birthday = new DateTime(2000, 1, 15); // 2000年1月15日 DateTime specificTime = new DateTime(2024, 5, 20, 14, 30, 0); // 2024年5月20日14:30:00 // 常用操作 TimeSpan duration = now - birthday; // 计算时间间隔 int days = duration.Days; // 相差天数 DateTime nextWeek = now.AddDays(7); // 加7天 string formatted = now.ToString("yyyy-MM-dd HH:mm:ss"); // 格式化输出 ``` | 1. 记录时间戳(如登录时间、操作时间);2. 时间计算(时间差、日期加减);3. 时间格式化显示;4. 时间戳转换(与Unix时间戳互转) | 1. DateTime.Now受本地时区影响,DateTime.UtcNow不受时区影响(推荐用于跨时区场景);2. 可空DateTime为DateTime?;3. 时间间隔用TimeSpan表示;4. 可通过ToUniversalTime()/ToLocalTime()进行UTC/本地时间转换;5. 避免使用DateTime.MinValue(0001年),推荐用可空类型表示“无时间” |
| DateTimeOffset | 日期时间偏移类型(System.DateTimeOffset),值类型,包含日期时间和该时间相对于UTC的偏移量,解决了DateTime的时区模糊问题 | ```csharp // 获取当前日期时间及偏移量(本地时区) DateTimeOffset now = DateTimeOffset.Now; Console.WriteLine(now); // 输出类似:2024-05-20 15:30:00 +08:00 // 获取UTC时间及偏移量 DateTimeOffset utcNow = DateTimeOffset.UtcNow; Console.WriteLine(utcNow); // 输出类似:2024-05-20 07:30:00 +00:00 // 构造指定偏移量的时间 DateTimeOffset dt = new DateTimeOffset(2024, 1, 1, 12, 0, 0, TimeSpan.FromHours(8)); // 转换为其他时区 DateTimeOffset nyTime = dt.ToOffset(TimeSpan.FromHours(-5)); // 转换为纽约时区(UTC-5) // 转换为Unix时间戳(秒/毫秒) long unixTimeSeconds = dt.ToUnixTimeSeconds(); long unixTimeMilliseconds = dt.ToUnixTimeMilliseconds(); // 解析字符串 DateTimeOffset parsed = DateTimeOffset.Parse("2024-05-20T15:30:00+08:00"); ``` | 1. 跨时区时间处理(如分布式系统中的时间同步);2. 需要明确时区偏移的时间记录(如日志时间、事件时间);3. Unix时间戳与本地时间的互转;4. 避免DateTime的“未指定”时区问题 | 1. 核心组成:DateTime(本地时间)、Offset(相对于UTC的偏移量);2. 比DateTime更精确的时区表示(DateTime的Kind属性无法精确表示所有时区);3. 支持时区转换(ToOffset())、Unix时间戳转换;4. 推荐用于跨时区场景,替代DateTime;5. 可通过ToUniversalTime()转换为UTC时间,ToLocalTime()转换为本地时间 |
| decimal | 128位高精度十进制浮点型(System.Decimal),专为金融计算设计 | csharp decimal amount = 199.99m; // 必须加m后缀 decimal tax = amount * 0.08m; | 金融计算(金额、税费、汇率)、需要精确小数运算的场景 | 1. 精度28-29位有效数字,无浮点误差;2. 需加m后缀;3. 运算速度比float/double慢 |
| Deconstruction(解构) | 解构(C# 7.0+),是一种语法特性,允许将对象或元组的多个字段/属性一次性提取到多个变量中,简化数据提取逻辑 | ```csharp // 1. 元组解构(最常用) var tuple = ("张三", 28, "男"); var (name, age, gender) = tuple; // 解构到三个变量 Console.WriteLine($"姓名:{name},年龄:{age},性别:{gender}"); // 2. 自定义类/结构体实现解构 public class Person { public string Name { get; set; } public int Age { get; set; } public string Gender { get; set; } // 实现解构方法(必须是void,名称为Deconstruct,参数为out参数) public void Deconstruct(out string name, out int age) { name = Name; age = Age; } // 可重载多个解构方法(不同参数个数) public void Deconstruct(out string name, out int age, out string gender) { name = Name; age = Age; gender = Gender; } } Person person = new Person { Name = "李四", Age = 22, Gender = "女" }; var (pName, pAge) = person; // 调用第一个解构方法 var (pName2, pAge2, pGender2) = person; // 调用第二个解构方法 Console.WriteLine($"姓名:{pName},年龄:{pAge}"); Console.WriteLine($"姓名:{pName2},年龄:{pAge2},性别:{pGender2}"); // 3. 忽略不需要的字段(用_表示) var (_, _, g) = tuple; Console.WriteLine($"性别:{g}"); ``` | 1. 元组多字段快速提取;2. 自定义对象的多属性批量提取;3. 方法返回多个值后的快速接收;4. 简化复杂对象的数据提取逻辑 | 1. 自定义类型实现解构需定义Deconstruct方法,参数为out类型(数量可自定义,支持重载);2. 解构时变量个数必须与Deconstruct方法的out参数个数匹配;3. 可通过下划线(_)忽略不需要的字段;4. 支持嵌套解构(如元组中包含元组,可多层解构);5. 解构是语法糖,本质是调用Deconstruct方法为out参数赋值 |
| delegates | 引用类型,用于封装具有特定签名的方法(方法指针) | csharp delegate int Calculate(int a, int b); Calculate add = (x,y)=>x+y; int result = add(5,3); | 1. 事件驱动编程(如按钮点击回调);2. 回调函数场景;3. 解耦方法调用 | 1. 可多播(+=添加方法、-=移除方法);2. 泛型委托(Func<>/Action<>)更简洁;3. 不能直接实例化抽象方法 |
| double | 64位双精度浮点型(System.Double),表示小数,范围±5.0×10⁻³²⁴~±1.7×10³⁰⁸ | csharp double pi = Math.PI; // 3.141592653589793 double distance = Math.Sqrt(3*3 + 4*4); | 高精度小数计算(科学计算、工程数据)、无需绝对精确的浮点场景 | 1. 精度约15-17位有效数字;2. 默认浮点常量类型(无需后缀);3. 存在浮点误差(如0.1+0.2≠0.3) |
| do-while | 循环语句关键字,先执行循环体,再判断条件(至少执行一次) | csharp int input; do { Console.Write("输入数字:"); } while (!int.TryParse(Console.ReadLine(), out input)); // 直到输入有效数字 | 至少执行一次的循环(如用户输入强制验证、初始化后校验) | 1. 循环体必执行一次;2. 条件表达式后必须加分号;3. 适合“先操作后判断”场景 |
| dynamic | 动态类型(System.Dynamic),编译时不进行类型检查,运行时动态解析成员 | csharp dynamic user = new ExpandoObject(); user.Name = "王五"; user.Age = 28; Console.WriteLine($"{user.Name}, {user.Age}"); dynamic jsonObj = JsonConvert.DeserializeObject(jsonStr); string title = jsonObj.Title; | 1. 动态数据交互(JSON/XML解析、COM组件调用);2. 跨语言调用;3. 避免大量类型转换的灵活场景 | 1. 运行时依赖DLR(动态语言运行时);2. 编译时不报错,运行时成员不存在会抛RuntimeBinderException;3. 性能略低于静态类型;4. 可与任意类型隐式转换 |
| Encoding | 编码类(System.Text.Encoding),抽象类,用于字符串与字节数组之间的编码转换(如UTF-8、GB2312、ASCII等编码格式) | ```csharp // 获取常用编码实例 Encoding utf8 = Encoding.UTF8; Encoding gbk = Encoding.GetEncoding("GBK"); Encoding ascii = Encoding.ASCII; // 字符串→字节数组(编码) string str = "你好,C#"; byte[] utf8Bytes = utf8.GetBytes(str); byte[] gbkBytes = gbk.GetBytes(str); // 字节数组→字符串(解码) string utf8Str = utf8.GetString(utf8Bytes); string gbkStr = gbk.GetString(gbkBytes); // 编码转换(GBK→UTF-8) byte[] convertedBytes = Encoding.Convert(gbk, utf8, gbkBytes); string convertedStr = utf8.GetString(convertedBytes); // 获取编码的预定义名称 Console.WriteLine(utf8.WebName); // utf-8 Console.WriteLine(gbk.WebName); // gb2312 ``` | 1. 字符串与字节流的转换(如文件读写、网络传输);2. 不同编码格式的文本处理(如GBK格式文件读取、UTF-8接口数据交互);3. 多语言文本编码(如中文、英文、特殊字符);4. 避免乱码问题(确保编码和解码使用同一格式) | 1. 常用编码:UTF8(推荐,支持全球字符)、ASCII(仅支持英文,不推荐)、GB2312/GBK(中文编码,Windows环境常用)、Unicode(UTF-16);2. 抽象类,不能直接实例化,需通过静态属性(如Encoding.UTF8)或GetEncoding()方法获取实例;3. 编码和解码必须使用同一编码格式,否则会出现乱码;4. UTF8编码默认带BOM(字节顺序标记),可通过new UTF8Encoding(false)创建无BOM的UTF8编码 |
| enum | 枚举类型(System.Enum),为整数常量定义友好名称,提高代码可读性 | csharp enum Gender { Male, Female, Other } Gender userGender = Gender.Male; int genderValue = (int)userGender; // 0 | 表示固定选项集合(性别、订单状态、角色类型),避免魔法数字 | 1. 默认底层类型为int,可指定(如enum Status : byte { Success=1, Fail=2 });2. 枚举值可自定义;3. 用Enum.IsDefined()判断是否有效 |
| enum(补充细节版) | 枚举类型(System.Enum),为一组相关的整数常量定义语义化名称,本质是值类型,默认底层类型为int | ```csharp // 指定底层类型为byte enum OrderStatus : byte { Pending = 1, Paid = 2, Shipped = 3, Completed = 4 } // 使用 OrderStatus status = OrderStatus.Paid; // 转换为底层类型 byte statusCode = (byte)status; // 从底层类型转换 OrderStatus newStatus = (OrderStatus)3; // 验证有效性 bool isValid = Enum.IsDefined(typeof(OrderStatus), 5); // false ``` | 1. 表示固定状态集合(订单状态、支付状态、错误码);2. 替代“魔法数字”提升代码可读性;3. 限制输入值范围 | 1. 底层类型可指定为byte、short、int、long等整数类型;2. 枚举值可自定义,未指定则从0开始递增;3. 支持位枚举(添加[Flags]特性,值为2的幂);4. 可通过Enum.GetValues()/Enum.GetNames()获取所有枚举值/名称 |
| Event | 事件关键字,基于委托的发布-订阅机制,用于实现对象间的松散耦合通信,本质是委托的封装(限制外部直接调用) | ```csharp // 定义委托(或使用内置EventHandler) public delegate void PriceChangedEventHandler(decimal oldPrice, decimal newPrice); public class Product { private decimal _price; // 定义事件 public event PriceChangedEventHandler PriceChanged; public decimal Price { get => _price; set { if (_price != value) { decimal old = _price; _price = value; // 触发事件(仅内部可调用) PriceChanged?.Invoke(old, value); } } } } // 订阅事件 var product = new Product(); product.PriceChanged += (oldPrice, newPrice) => Console.WriteLine($"价格从{oldPrice}变为{newPrice}"); product.Price = 199.99m; ``` | 1. 事件驱动编程(UI按钮点击、数据变更通知);2. 观察者模式实现(发布者通知多个订阅者);3. 模块间解耦通信(如服务状态变更通知) | 1. 事件只能在定义它的类内部触发(Invoke),外部只能订阅(+=)或取消订阅(-=);2. 推荐使用内置EventHandler<TEventArgs>委托,无需自定义委托;3. 可定义自定义事件参数(继承EventArgs)传递额外数据;4. 未订阅的事件为null,触发前需判空(?.Invoke()) |
| EventArgs | 事件参数基类(System.EventArgs),用于在事件触发时传递额外数据,是所有自定义事件参数的父类 | ```csharp // 自定义事件参数(继承EventArgs) public class UserLoginEventArgs : EventArgs { public string UserName { get; } public DateTime LoginTime { get; } public UserLoginEventArgs(string userName, DateTime loginTime) { UserName = userName; LoginTime = loginTime; } } // 定义事件(使用内置EventHandler) public event EventHandler<UserLoginEventArgs> UserLoggedIn; // 触发事件 UserLoggedIn?.Invoke(this, new UserLoginEventArgs("张三", DateTime.Now)); // 订阅事件 obj.UserLoggedIn += (sender, e) => Console.WriteLine($"用户{e.UserName}于{e.LoginTime}登录"); ``` | 1. 事件需要传递额外数据的场景(登录用户信息、数据变更详情);2. 遵循.NET事件标准模式(sender + EventArgs);3. 统一事件参数传递规范 | 1. 无参数事件可直接使用EventArgs.Empty;2. 自定义事件参数必须继承EventArgs;3. 内置EventHandler<T>委托的第二个参数即为EventArgs子类;4. 支持传递任意复杂数据(属性、集合等) |
| ExpandoObject | 动态扩展对象(System.Dynamic.ExpandoObject),实现IDynamicMetaObjectProvider接口,允许动态添加、删除、修改属性和方法,是C#中最简单的动态对象实现 | ```csharp // 1. 创建ExpandoObject dynamic expando = new ExpandoObject(); // 2. 动态添加属性 expando.Id = 1; expando.Name = "产品A"; expando.Price = 99.99m; // 访问属性 Console.WriteLine($"ID:{expando.Id},名称:{expando.Name},价格:{expando.Price}"); // 3. 动态添加方法 expando.CalculateTotal = new Func<int, decimal>((count) => expando.Price * count); decimal total = expando.CalculateTotal(5); Console.WriteLine($"5件产品总价:{total}"); // 499.95 // 4. 动态添加委托属性 expando.OnPriceChanged = new Action<decimal, decimal>((oldPrice, newPrice) => { Console.WriteLine($"价格从{oldPrice}变更为{newPrice}"); }); // 修改属性并触发委托 decimal oldPrice = expando.Price; expando.Price = 89.99m; expando.OnPriceChanged(oldPrice, expando.Price); // 输出价格变更信息 // 5. 转换为IDictionary<string, object>操作 IDictionary<string, object> expandoDict = expando as IDictionary<string, object>; // 检查属性是否存在 if (expandoDict.ContainsKey("Name")) { Console.WriteLine($"Name属性值:{expandoDict["Name"]}"); } // 添加属性(通过字典) expandoDict["Stock"] = 100; Console.WriteLine($"库存:{expando.Stock}"); // 100 // 删除属性(通过字典) expandoDict.Remove("Price"); // Console.WriteLine(expando.Price); // 运行时异常:属性不存在 // 6. 动态对象集合 List<dynamic> products = new List<dynamic>(); products.Add(expando); dynamic product2 = new ExpandoObject(); product2.Id = 2; product2.Name = "产品B"; products.Add(product2); foreach (var p in products) { Console.WriteLine($"产品ID:{p.Id},名称:{p.Name}"); } ``` | 1. 动态配置对象(如配置文件解析后的动态存储);2. 动态数据载体(如API返回的非固定格式数据);3. 简化临时对象创建(无需定义类);4. 动态UI绑定(如MVVM框架中的动态视图模型);5. 插件系统中的动态扩展(插件动态添加属性和方法) | 1. 核心特性:可动态添加/删除/修改属性和方法,实现了IDictionary<string, object>接口(可通过字典方式操作);2. 与DynamicObject的区别:ExpandoObject是现成的动态对象实现(开箱即用),DynamicObject需要继承并重写方法自定义动态行为;3. 性能:比静态类型慢,但比自定义DynamicObject快(内置优化);4. 序列化:支持JSON序列化(如Newtonsoft.Json可直接序列化ExpandoObject为JSON对象);5. 限制:不支持静态成员、不支持接口实现、不支持方法重载的自动解析(需手动处理);6. 适用场景:临时的、结构不固定的对象场景,避免在性能敏感场景使用;7. 命名空间:System.Dynamic,需添加对应using语句,且项目需引用System.Core.dll |
| explicit | 显式转换运算符,用于自定义类型的强制类型转换(需手动指定转换) | csharp public class Meter { public double Value { get; set; } public static explicit operator Centimeter(Meter m) { return new Centimeter { Value = m.Value * 100 }; } } Meter m = new(){ Value = 2 }; Centimeter cm = (Centimeter)m; // 显式转换 | 1. 可能丢失精度或数据的类型转换;2. 自定义类型间的非隐式转换;3. 明确转换意图的场景 | 1. 转换需手动写强制转换符(());2. 与implicit(隐式转换)相对;3. 转换过程中可添加校验逻辑(如抛出异常);4. 必须在自定义类型中定义 |
| Expression<Func<T>> | 表达式树(System.Linq.Expressions.Expression<Func<T>>),将Lambda表达式表示为抽象语法树(AST),可在运行时解析、修改和编译执行,是动态构建逻辑的核心 | ```csharp // 定义表达式树 Expression<Func<int, bool>> isGreaterThan5 = x => x > 5; // 解析表达式树结构 BinaryExpression binaryExpr = (BinaryExpression)isGreaterThan5.Body; ParameterExpression paramExpr = (ParameterExpression)binaryExpr.Left; ConstantExpression constExpr = (ConstantExpression)binaryExpr.Right; Console.WriteLine($"参数:{paramExpr.Name}"); // x Console.WriteLine($"运算符:{binaryExpr.NodeType}"); // GreaterThan Console.WriteLine($"常量:{constExpr.Value}"); // 5 // 编译表达式树为委托并执行 Func<int, bool> func = isGreaterThan5.Compile(); bool result = func(6); // true // 动态构建表达式树(x => x + 3) ParameterExpression param = Expression.Parameter(typeof(int), "x"); ConstantExpression constant = Expression.Constant(3, typeof(int)); BinaryExpression addExpr = Expression.Add(param, constant); Expression<Func<int, int>> addExpression = Expression.Lambda<Func<int, int>>(addExpr, param); Func<int, int> addFunc = addExpression.Compile(); Console.WriteLine(addFunc(4)); // 7 ``` | 1. ORM框架核心(如EF Core,将Lambda表达式转换为SQL语句);2. 动态构建查询条件(如多条件组合查询);3. 运行时解析和修改逻辑(如规则引擎);4. 代码生成和动态执行场景 | 1. 表达式树与委托的区别:委托是编译后的可执行代码,表达式树是可解析的语法树结构;2. 核心类:Expression(抽象基类)、ParameterExpression(参数)、ConstantExpression(常量)、BinaryExpression(二元运算)等;3. 需通过Compile()方法将表达式树转换为委托才能执行;4. 仅支持Lambda表达式的子集(不支持多语句、循环等复杂逻辑);5. 属于System.Linq.Expressions命名空间,需引用System.Core.dll |
| Extension Methods(扩展方法) | C#特性,允许在不修改原有类型(包括密封类)、不继承原有类型的前提下,为类型添加新方法,扩展方法必须定义在静态类中,且第一个参数带有this关键字(指定扩展的目标类型) | ```csharp // 1. 定义扩展方法(必须在静态类中) public static class StringExtensions { // 为string类型添加扩展方法:判断是否为邮箱格式 public static bool IsEmail(this string str) { if (string.IsNullOrWhiteSpace(str)) return false; string pattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"; return Regex.IsMatch(str, pattern); } // 为string类型添加扩展方法:首字母大写 public static string FirstLetterToUpper(this string str) { if (string.IsNullOrWhiteSpace(str)) return str; return char.ToUpper(str[0]) + str.Substring(1).ToLower(); } } // 为int类型添加扩展方法 public static class IntExtensions { // 判断整数是否为偶数 public static bool IsEven(this int num) { return num % 2 == 0; } // 将整数转换为中文数字(简化版) public static string ToChineseNumber(this int num) { if (num < 0 || num > 9) return num.ToString(); char[] chineseNums = { '零', '一', '二', '三', '四', '五', '六', '七', '八', '九' }; return chineseNums[num].ToString(); } } // 2. 使用扩展方法(直接像原有方法一样调用) string email1 = "test@example.com"; string email2 = "invalid-email"; Console.WriteLine($"email1是否为邮箱:{email1.IsEmail()}"); // True Console.WriteLine($"email2是否为邮箱:{email2.IsEmail()}"); // False string name = "zhangsan"; Console.WriteLine(name.FirstLetterToUpper()); // Zhangsan int num1 = 8; int num2 = 7; Console.WriteLine($"{num1}是否为偶数:{num1.IsEven()}"); // True Console.WriteLine($"{num2}是否为偶数:{num2.IsEven()}"); // False Console.WriteLine($"{num1}的中文数字:{num1.ToChineseNumber()}"); // 八 // 3. 扩展方法与实例方法同名时,实例方法优先 public class MyClass { public void Print() { Console.WriteLine("实例方法Print"); } } public static class MyClassExtensions { public static void Print(this MyClass obj) { Console.WriteLine("扩展方法Print"); } } MyClass obj = new MyClass(); obj.Print(); // 输出:实例方法Print ``` | 1. 扩展现有类型功能(如为string、int等内置类型添加业务相关方法);2. 扩展密封类(无法继承的类)的功能;3. 不修改原有代码的前提下扩展第三方库类型;4. LINQ核心实现(如Where、Select等LINQ方法均为IEnumerable<T>的扩展方法);5. 业务逻辑复用(将通用业务逻辑封装为扩展方法) | 1. 定义规则:扩展方法必须在静态类中,方法本身必须是static,第一个参数必须带this关键字(this 目标类型 参数名);2. 调用规则:扩展方法可直接通过目标类型实例调用,无需传递第一个this参数;3. 优先级:实例方法优先级高于同名扩展方法,若类型已有同名实例方法,扩展方法不会被调用;4. 查找规则:扩展方法的可见性取决于静态类的访问修饰符(public/private等),需确保静态类在调用处可见;5. 限制:不能扩展接口的实现方法;不能访问目标类型的私有成员;6. 最佳实践:扩展方法命名建议添加明确语义(避免歧义),将相关扩展方法放在同一静态类中(如StringExtensions、IntExtensions) |
| fixed | 固定语句关键字,用于锁定托管对象的内存地址(unsafe代码中使用),避免GC移动 | csharp unsafe { string str = "Hello"; fixed (char* p = str) { for (int i = 0; p[i] != '\0'; i++) { Console.Write(p[i]); } } fixed (int* p = new int[5]) { p[0] = 1; } | 1. unsafe代码中操作托管对象指针;2. 固定数组、字符串等托管类型地址;3. 非托管内存拷贝 | 1. 仅在unsafe代码块中使用;2. 固定期间对象不会被GC回收或移动;3. 代码块结束后自动解锁;4. 可固定多个对象(fixed (int* p1 = arr1, *p2 = arr2)) |
| float | 32位单精度浮点型(System.Single),表示小数,范围±1.5×10⁻⁴⁵~±3.4×10³⁸ | csharp float price = 99.9f; // 必须加f后缀 float average = (10.5f + 20.3f) / 2; | 存储精度要求不高的小数(商品价格、简单计算结果),节省内存 | 1. 精度约6-9位有效数字;2. 需加f后缀(否则编译器视为double);3. 避免用于金融计算(用decimal) |
| for | 循环语句关键字,用于已知循环次数的迭代(初始化+条件判断+迭代器) | csharp int sum = 0; for (int i = 1; i <= 100; i++) { sum += i; } // 1-100求和 | 固定次数循环(数组遍历、批量处理固定数量数据)、精确控制循环步长 | 1. 三个表达式均可省略(如for(;;)为无限循环);2. 初始化变量作用域仅限循环内;3. 可嵌套循环(多层遍历) |
| foreach | 迭代遍历集合(实现IEnumerable/IEnumerable<T>的类型) | csharp List<string> names = new(){"A","B","C"}; foreach (var name in names) { Console.WriteLine(name); } // 数组遍历 int[] nums = {1,2,3}; foreach (var num in nums) { sum += num; } | 遍历数组、List、Dictionary等集合,无需手动管理索引 | 1. 遍历过程中不能修改集合(会抛InvalidOperationException);2. 比for循环简洁,适合只读遍历;3. 本质是调用GetEnumerator()方法 |
| Func<> | 泛型委托(System.Func),用于封装有返回值的方法,参数个数0-16个,最后一个泛型参数为返回值类型 | ```csharp // 无参数,返回string Func<string> getCurrentTime = () => DateTime.Now.ToString("HH:mm:ss"); // 1个参数,返回int(求平方) Func<int, int> square = x => x * x; // 2个参数,返回bool(比较大小) Func<int, int, bool> isGreater = (a, b) => a > b; // 调用 Console.WriteLine(getCurrentTime()); // 输出当前时间 Console.WriteLine(square(5)); // 25 Console.WriteLine(isGreater(10, 5)); // true ``` | 1. LINQ查询(Where、Select、Aggregate等方法的参数);2. 有返回值的回调函数;3. 简化自定义有返回值委托的定义;4. 匿名方法/ lambda表达式的常用载体 | 1. 无参数有返回值:Func<TResult>;2. 有参数有返回值:Func<T1, T2, ..., TResult>;3. 不能用于无返回值的方法(无返回值用Action<>);4. 是.NET内置委托,无需手动定义,直接使用 |
| goto | 跳转语句关键字,用于无条件跳转到指定标签(label)处执行代码 | csharp int i = 0; loop: Console.WriteLine(i); i++; if (i < 5) goto loop; // 跳转到loop标签 | 简化多层循环退出、特定流程跳转(如状态机) | 1. 避免滥用(破坏代码结构化);2. 不能跳转到循环/try块内部;3. 可用于switch穿透控制 |
| Guid | 值类型(System.Guid),表示全局唯一标识符(Globally Unique Identifier),是128位的数字,用于确保对象标识的唯一性 | ```csharp // 生成新的Guid Guid id1 = Guid.NewGuid(); Console.WriteLine(id1); // 输出类似:84E9A7C4-7D8A-4F9B-9E8C-1234567890AB // 从字符串解析Guid string guidStr = "84E9A7C4-7D8A-4F9B-9E8C-1234567890AB"; if (Guid.TryParse(guidStr, out Guid id2)) { Console.WriteLine("解析成功:" + id2); } // 空Guid(全0) Guid emptyGuid = Guid.Empty; bool isEmpty = id1 == Guid.Empty; // false // 用于对象标识 public class User { public Guid Id { get; set; } = Guid.NewGuid(); // 初始化时生成唯一ID public string Name { get; set; } } ``` | 1. 数据库主键(避免ID冲突,尤其分布式系统);2. 唯一文件名(如上传文件命名);3. 分布式系统中的对象唯一标识;4. 避免重复的唯一编号生成(如订单号、任务ID) | 1. Guid.NewGuid()生成的Guid几乎不可能重复(全球唯一);2. 支持多种格式字符串(如"N"无分隔符、"D"带连字符、"B"带大括号);3. Guid.Empty表示空Guid(全0),可用于判断是否未赋值;4. 生成速度快,无需中心化ID生成服务;5. 不支持排序(如需排序推荐用雪花算法) |
| HashSet<> | 泛型哈希集合(System.Collections.Generic.HashSet<T>),实现ICollection<T>,基于哈希表实现,存储不重复的元素,支持快速查找 | ```csharp // 初始化哈希集合(自动去重) HashSet<int> numbers = new HashSet<int> { 1, 2, 3, 3, 4 }; Console.WriteLine(numbers.Count); // 4(重复的3被移除) // 添加元素(重复添加返回false) bool added = numbers.Add(5); // true added = numbers.Add(2); // false(已存在) // 集合运算(交集、并集、差集) HashSet<int> other = new HashSet<int> { 3, 4, 6 }; numbers.IntersectWith(other); // 交集:{3,4} // numbers.UnionWith(other); // 并集:{1,2,3,4,5,6} // numbers.ExceptWith(other); // 差集:{1,2,5} // 快速查找 bool contains = numbers.Contains(3); // true ``` | 1. 数据去重场景(如去重列表、唯一标识存储);2. 快速查找元素(时间复杂度O(1));3. 集合运算(交集、并集、差集、子集判断);4. 无需排序的唯一元素存储 | 1. 元素必须重写GetHashCode()和Equals()方法(否则无法正确判断重复,引用类型默认比较地址);2. 不保证元素顺序(如需有序用SortedSet<T>);3. 不支持索引访问;4. 比List<T>的Contains()方法性能更高(哈希查找 vs 线性查找) |
| HashSet<T> | 泛型哈希集合(System.Collections.Generic.HashSet<T>),基于哈希表实现的集合,用于存储不重复的元素,支持O(1)时间复杂度的添加、删除、查找操作,不保证元素顺序 | ```csharp // 1. 初始化HashSet<T> HashSet<int> numbers = new HashSet<int>(); // 2. 添加元素(自动去重) numbers.Add(1); numbers.Add(2); numbers.Add(3); bool isAdded = numbers.Add(2); // 重复元素,添加失败 Console.WriteLine($"添加2是否成功:{isAdded}"); // False Console.WriteLine($"HashSet元素:{string.Join(",", numbers)}"); // 1,2,3(顺序不保证) // 3. 查找元素(O(1)时间复杂度) bool contains3 = numbers.Contains(3); Console.WriteLine($"是否包含3:{contains3}"); // True // 4. 删除元素 bool isRemoved = numbers.Remove(2); Console.WriteLine($"删除2是否成功:{isRemoved}"); // True Console.WriteLine($"删除后元素:{string.Join(",", numbers)}"); // 1,3 // 5. 集合运算(交集、并集、差集) HashSet<int> set1 = new HashSet<int> { 1, 2, 3, 4 }; HashSet<int> set2 = new HashSet<int> { 3, 4, 5, 6 }; // 交集(两个集合共有的元素) set1.IntersectWith(set2); Console.WriteLine($"交集:{string.Join(",", set1)}"); // 3,4 // 重置set1 set1 = new HashSet<int> { 1, 2, 3, 4 }; // 并集(两个集合的所有元素,去重) set1.UnionWith(set2); Console.WriteLine($"并集:{string.Join(",", set1)}"); // 1,2,3,4,5,6 // 重置set1 set1 = new HashSet<int> { 1, 2, 3, 4 }; // 差集(set1中有但set2中没有的元素) set1.ExceptWith(set2); Console.WriteLine($"差集:{string.Join(",", set1)}"); // 1,2 // 6. 其他常用操作 HashSet<string> strSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); // 忽略大小写 strSet.Add("Hello"); bool containshello = strSet.Contains("hello"); Console.WriteLine($"是否包含hello(忽略大小写):{containshello}"); // True // 转换为数组 int[] arr = numbers.ToArray(); Console.WriteLine($"转换为数组:{string.Join(",", arr)}"); // 1,3 ``` | 1. 去重场景(如存储不重复的ID、名称);2. 快速查找场景(需要O(1)查找效率);3. 集合运算场景(交集、并集、差集计算);4. 避免重复添加的场景(如批量数据处理中的去重) | 1. 底层实现:基于哈希表,每个元素的位置由哈希码决定,因此查找、添加、删除效率高(O(1));2. 去重机制:通过IEqualityComparer<T>比较元素是否相等,默认使用EqualityComparer<T>.Default;3. 集合运算:支持IntersectWith(交集)、UnionWith(并集)、ExceptWith(差集)、SymmetricExceptWith(对称差集)等;4. 与List<T>的区别:List<T>允许重复元素,查找效率O(n);HashSet<T>不允许重复元素,查找效率O(1);5. 顺序:不保证元素的插入顺序或排序顺序,若需要有序集合,可使用SortedSet<T>;6. 性能优化:初始化时指定初始容量(避免频繁扩容),使用合适的IEqualityComparer<T>(如忽略大小写的字符串比较);7. 常用方法:Add()、Contains()、Remove()、Clear()、Count(元素个数) |
| IAsyncDisposable | 异步释放资源接口(System.IAsyncDisposable,C# 8.0+),定义了异步释放非托管资源的方法,用于释放需要异步操作的资源(如异步文件句柄、网络连接) | ```csharp // 实现IAsyncDisposable接口 public class AsyncFileHandler : IAsyncDisposable, IDisposable { private FileStream _stream; public AsyncFileHandler(string filePath) { _stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true); } // 异步读取数据(示例方法) public async Task<byte[]> ReadAsync(int count) { byte[] buffer = new byte[count]; int bytesRead = await _stream.ReadAsync(buffer, 0, count); Array.Resize(ref buffer, bytesRead); return buffer; } // 实现IAsyncDisposable接口 public async ValueTask DisposeAsync() { await DisposeAsyncCore(); // 抑制终结器(如果有) GC.SuppressFinalize(this); } // 核心异步释放逻辑 protected virtual async ValueTask DisposeAsyncCore() { if (_stream != null) { await _stream.DisposeAsync(); // 异步释放FileStream _stream = null; } } // 实现IDisposable(兼容同步场景) public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing && _stream != null) { _stream.Dispose(); // 同步释放 _stream = null; } } // 终结器(可选) ~AsyncFileHandler() { Dispose(false); } } // 使用IAsyncDisposable(await using语句) async Task UseAsyncFileHandler() { // await using自动调用DisposeAsync() await using (var handler = new AsyncFileHandler("data.txt")) { byte[] data = await handler.ReadAsync(1024); Console.WriteLine($"读取到{data.Length}字节数据"); } // 退出using块,自动调用handler.DisposeAsync() // 简化语法(C# 9.0+) await using var handler2 = new AsyncFileHandler("data.txt"); byte[] data2 = await handler2.ReadAsync(512); } // 调用异步方法 await UseAsyncFileHandler(); ``` | 1. 异步操作非托管资源的场景(如异步文件读写、异步网络通信);2. 避免同步释放资源导致的线程阻塞;3. 配合Async/Await实现全异步资源管理;4. .NET Core/.NET 5+中的异步IO资源(如FileStream、HttpClient的异步释放) | 1. 核心方法:ValueTask DisposeAsync(),返回ValueTask(值类型任务,减少内存分配);2. 使用方式:通过await using语句(C# 8.0+),自动调用DisposeAsync(),即使发生异常;3. 兼容建议:同时实现IDisposable接口,支持同步释放场景;4. 释放逻辑:优先释放异步资源(如调用DisposeAsync()方法),再处理同步资源;5. 与IDisposable的区别:IDisposable用于同步释放资源,IAsyncDisposable用于异步释放资源;6. 常用实现类:FileStream(异步模式)、HttpClient(.NET 5+支持)、SqlConnection(异步释放连接) |
| ICollection<> | 泛型集合接口(System.Collections.Generic.ICollection<T>),继承自IEnumerable<T>,定义了可获取集合大小、添加、删除元素及判断元素是否存在的规范 | ```csharp // 实例化ICollection<T>实现类(HashSet<T>) ICollection<int> numbers = new HashSet<int> { 1, 2, 3, 4 }; // 获取集合大小 int count = numbers.Count; // 4 // 添加/删除 bool added = numbers.Add(5); // true(添加成功) bool removed = numbers.Remove(2); // true(删除成功) // 判断元素是否存在 bool contains = numbers.Contains(3); // true // 复制到数组 int[] arr = new int[numbers.Count]; numbers.CopyTo(arr, 0); ``` | 1. 需要统一集合增删、计数、包含判断功能的场景;2. 方法参数中接受多种集合类型(只要实现ICollection<T>);3. 无需索引访问的集合操作(如HashSet、Queue等);4. 自定义集合的基础接口实现 | 1. 核心成员:Count(集合大小)、Add()、Remove()、Contains()、CopyTo();2. 部分实现类是只读的(如ReadOnlyCollection),Add/Remove会抛NotSupportedException;3. 继承自IEnumerable<T>,支持foreach遍历;4. 与IList<T>的区别:无索引访问功能 |
| IComparable<> | 泛型比较接口(System.IComparable<T>),定义了类型实例之间的比较方法,用于指定对象的默认排序规则 | ```csharp // 自定义类实现IComparable<T>(按Age升序) public class Person : IComparable<Person> { public string Name { get; set; } public int Age { get; set; } public int CompareTo(Person other) { if (other == null) return 1; // null视为小于当前对象 return Age.CompareTo(other.Age); // 按Age升序排序 } } // 使用 List<Person> people = new List<Person> { new Person { Name = "张三", Age = 28 }, new Person { Name = "李四", Age = 22 }, new Person { Name = "王五", Age = 30 } }; people.Sort(); // 按Age升序排序 foreach (var p in people) { Console.WriteLine($"{p.Name}: {p.Age}"); // 李四(22)、张三(28)、王五(30) } ``` | 1. 自定义类型需要排序的场景(如List.Sort()、SortedSet存储);2. 统一对象的比较规则;3. 支持默认排序的集合存储自定义对象;4. 比较两个自定义对象的大小关系 | 1. 核心方法:CompareTo(T other),返回int值(负:当前对象小;零:相等;正:当前对象大);2. 非泛型版本为IComparable,泛型版本更类型安全(避免装箱拆箱);3. 若不实现此接口,直接排序会抛InvalidOperationException;4. 可配合IComparer<T>实现自定义排序(覆盖默认规则) |
| IComparer<> | 泛型比较器接口(System.Collections.Generic.IComparer<T>),定义了两个对象之间的比较方法,用于实现自定义排序规则(覆盖默认排序) | ```csharp // 自定义比较器(按Person的Name长度降序) public class PersonNameLengthComparer : IComparer<Person> { public int Compare(Person x, Person y) { if (x == null && y == null) return 0; if (x == null) return -1; if (y == null) return 1; return y.Name.Length.CompareTo(x.Name.Length); // 降序 } } // 使用 List<Person> people = new List<Person> { new Person { Name = "张三", Age = 28 }, new Person { Name = "李四四", Age = 22 }, new Person { Name = "王", Age = 30 } }; // 使用自定义比较器排序 people.Sort(new PersonNameLengthComparer()); foreach (var p in people) { Console.WriteLine($"{p.Name}: {p.Name.Length}"); // 李四四(3)、张三(2)、王(1) } ``` | 1. 自定义类型需要多种排序规则的场景(如按年龄升序、按姓名降序);2. 覆盖默认排序规则(IComparable<T>定义的规则);3. 排序方法中指定比较逻辑(如List.Sort()、Array.Sort());4. 动态切换排序规则 | 1. 核心方法:Compare(T x, T y),返回int值(负:x小;零:相等;正:x大);2. 与IComparable<T>的区别:IComparable是对象自身的排序规则,IComparer是外部的比较规则;3. .NET提供默认实现:Comparer<T>.Default(使用IComparable<T>的规则);4. 可通过匿名方法/ lambda简化实现(无需定义类) |
| IDictionary<,> | 泛型字典接口(System.Collections.Generic.IDictionary<TKey, TValue>),继承自ICollection<KeyValuePair<TKey, TValue>>,定义了键值对集合的操作规范,支持通过键访问值 | ```csharp // 实例化IDictionary实现类(Dictionary<TKey, TValue>) IDictionary<string, int> studentScores = new Dictionary<string, int> { { "张三", 90 }, { "李四", 85 } }; // 通过键访问/修改值 studentScores["王五"] = 95; // 添加新键值对 int score = studentScores["张三"]; // 90 // 遍历键值对 foreach (var kvp in studentScores) { Console.WriteLine($"{kvp.Key}: {kvp.Value}"); } // 判断键是否存在 if (studentScores.ContainsKey("赵六")) { studentScores.Remove("赵六"); } ``` | 1. 键值对映射场景(如用户ID-用户信息、名称-数值);2. 快速查找(通过键查找值,时间复杂度O(1));3. 数据去重(键唯一);4. 配置项存储、缓存数据等场景 | 1. 核心要求:键必须唯一,不能为空引用(值类型键不能为null);2. 常用实现类:Dictionary<TKey,TValue>、SortedDictionary(有序)、ConcurrentDictionary(线程安全);3. 继承自ICollection,支持计数、复制到数组;4. 通过KeyValuePair<TKey,TValue>表示单个键值对 |
| IDisposable | 释放资源接口(System.IDisposable),定义了释放非托管资源的方法,用于在对象生命周期结束时手动释放资源(如文件句柄、数据库连接、网络连接) | ```csharp // 自定义类实现IDisposable(释放文件资源) public class FileHandler : IDisposable { private FileStream _stream; private bool _disposed = false; public FileHandler(string filePath) { _stream = new FileStream(filePath, FileMode.Open); } // 实现IDisposable接口 public void Dispose() { Dispose(true); GC.SuppressFinalize(this); // 通知GC无需执行终结器 } // 核心释放逻辑(区分手动释放和GC释放) protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { // 释放托管资源(实现IDisposable的资源) _stream?.Dispose(); } // 释放非托管资源(如句柄、指针等,此处无) _disposed = true; } } // 终结器(防止忘记手动Dispose,GC回收时释放资源) ~FileHandler() { Dispose(false); } } // 使用(using语句自动调用Dispose) using (var handler = new FileHandler("data.txt")) { // 操作文件 } // 退出using块自动调用handler.Dispose() ``` | 1. 封装非托管资源的类(如文件操作、数据库连接、网络通信);2. 避免资源泄漏(非托管资源不会被GC自动回收);3. 手动控制资源释放时机;4. 配合using语句实现自动资源释放 | 1. 核心方法:Dispose(),用于手动释放资源;2. 推荐实现“Dispose模式”:包含Dispose(bool)方法、终结器(~类名)、_disposed标记;3. using语句会自动调用IDisposable.Dispose(),即使发生异常;4. 托管资源(实现IDisposable)在disposing=true时释放,非托管资源在disposing=false时释放;5. GC.SuppressFinalize()用于避免GC重复释放资源 |
| IEnumerable<> | 泛型接口(System.Collections.Generic.IEnumerable<T>),定义了获取枚举器的方法,支持foreach遍历,是所有泛型集合的基接口 | ```csharp // 实现IEnumerable<T>的集合(List、Array、HashSet等) IEnumerable<int> numbers = new List<int> { 1, 2, 3, 4 }; // foreach遍历 foreach (int num in numbers) { Console.WriteLine(num); } // 自定义实现IEnumerable<T> public class MyCollection : IEnumerable<int> { private int[] _data = { 10, 20, 30 }; public IEnumerator<int> GetEnumerator() { foreach (int item in _data) { yield return item; // 使用yield简化枚举器实现 } } // 显式实现非泛型IEnumerable接口 IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } ``` | 1. 支持foreach遍历的集合定义;2. LINQ查询的基础(所有LINQ方法均扩展自IEnumerable<T>);3. 统一集合的遍历接口(不同集合统一遍历方式);4. 延迟加载数据(如通过yield实现的动态数据生成) | 1. 核心方法:GetEnumerator(),返回IEnumerator<T>枚举器;2. 继承自非泛型IEnumerable接口;3. 支持延迟执行(如LINQ查询在遍历时时才执行);4. 只读接口,仅支持遍历,不支持添加/删除元素;5. 大部分.NET集合(List、Array、Dictionary等)均实现此接口 |
| IEnumerator<> | 泛型枚举器接口(System.Collections.Generic.IEnumerator<T>),定义了遍历集合的方法(获取当前元素、移动到下一个元素、释放资源),配合IEnumerable<>使用 | ```csharp // 获取枚举器 IEnumerable<int> numbers = new int[] { 1, 2, 3 }; IEnumerator<int> enumerator = numbers.GetEnumerator(); // 手动遍历(foreach的底层实现) try { while (enumerator.MoveNext()) { int current = enumerator.Current; Console.WriteLine(current); // 输出1、2、3 } } finally { // 释放资源(枚举器实现了IDisposable) enumerator.Dispose(); } // 自定义枚举器(通常通过yield自动生成) public IEnumerator<string> GetNamesEnumerator() { yield return "张三"; yield return "李四"; yield return "王五"; } ``` | 1. 自定义集合的遍历实现;2. 手动控制遍历过程(如中断、重置);3. foreach循环的底层依赖;4. 延迟加载数据的遍历支持 | 1. 核心成员:MoveNext()(移动到下一个元素,返回bool)、Current(获取当前元素)、Dispose()(释放资源);2. 枚举器是一次性的(实现IDisposable),遍历完成后需释放;3. 通常无需手动实现,通过yield关键字可自动生成;4. 非泛型版本为IEnumerator,泛型版本更类型安全(避免装箱拆箱) |
| IEquatable<> | 泛型相等性接口(System.IEquatable<T>),定义了对象之间的相等性判断方法,用于替代默认的Equals()方法,提高相等性判断的性能和类型安全性 | ```csharp // 自定义类实现IEquatable<T>(按Id判断相等) public class User : IEquatable<User> { public int Id { get; set; } public string Name { get; set; } public bool Equals(User other) { if (other == null) return false; return Id == other.Id; // 按Id判断相等,忽略Name } // 重写Object的Equals和GetHashCode(必须配套重写) public override bool Equals(object obj) => Equals(obj as User); public override int GetHashCode() => Id.GetHashCode(); } // 使用 User u1 = new User { Id = 1, Name = "张三" }; User u2 = new User { Id = 1, Name = "张三三" }; User u3 = new User { Id = 2, Name = "张三" }; Console.WriteLine(u1.Equals(u2)); // true(Id相同) Console.WriteLine(u1.Equals(u3)); // false(Id不同) HashSet<User> users = new HashSet<User> { u1, u2 }; Console.WriteLine(users.Count); // 1(u2被视为重复元素) ``` | 1. 自定义类型需要自定义相等性判断的场景(如按特定字段判断相等);2. 提高值类型相等性判断的性能(避免装箱);3. 集合去重(如HashSet<T>、Dictionary<TKey,TValue>)的正确判断;4. 替代Object.Equals()的类型不安全判断 | 1. 核心方法:Equals(T other),返回bool值表示是否相等;2. 实现此接口时必须配套重写Object.Equals()和Object.GetHashCode()方法(保证一致性);3. 泛型版本比非泛型Equals()性能更高(无装箱拆箱);4. 集合(如HashSet)会优先使用IEquatable<T>.Equals()判断重复 |
| IFormatter | 格式化接口(System.Runtime.Serialization.IFormatter),定义了对象的序列化和反序列化方法,用于将对象转换为字节流(序列化)或从字节流还原对象(反序列化) | ```csharp // 使用BinaryFormatter(实现IFormatter)进行序列化/反序列化 using System.Runtime.Serialization.Formatters.Binary; using System.IO; // 需序列化的类(标记[Serializable]) [Serializable] public class Product { public string Name { get; set; } public decimal Price { get; set; } } // 序列化(对象→字节流) IFormatter formatter = new BinaryFormatter(); using (Stream stream = new FileStream("product.bin", FileMode.Create)) { Product product = new Product { Name = "手机", Price = 2999.99m }; formatter.Serialize(stream, product); } // 反序列化(字节流→对象) using (Stream stream = new FileStream("product.bin", FileMode.Open)) { Product deserializedProduct = (Product)formatter.Deserialize(stream); Console.WriteLine($"{deserializedProduct.Name}: {deserializedProduct.Price}"); } ``` | 1. 对象持久化(如保存对象到文件、数据库);2. 跨进程/跨网络传输对象(如分布式系统中的数据传输);3. 对象深拷贝;4. 统一序列化/反序列化接口(适配不同格式化器) | 1. 核心方法:Serialize(Stream, object)(序列化)、Deserialize(Stream)(反序列化);2. 常用实现类:BinaryFormatter(二进制序列化,不推荐用于不可信环境)、XmlSerializer(XML序列化,不实现IFormatter但功能类似)、JsonSerializer(JSON序列化);3. 序列化的类必须标记[Serializable]特性(BinaryFormatter要求);4. 可通过[NonSerialized]特性排除不需要序列化的字段 |
| IList<> | 泛型列表接口(System.Collections.Generic.IList<T>),继承自IEnumerable<T>和ICollection<T>,定义了可通过索引访问、添加、删除元素的集合规范 | ```csharp // 实例化实现IList<T>的集合(List<T>) IList<string> fruits = new List<string> { "苹果", "香蕉", "橙子" }; // 索引访问 string first = fruits[0]; // 苹果 fruits[1] = "葡萄"; // 修改索引1的元素 // 添加/删除 fruits.Add("芒果"); fruits.RemoveAt(2); // 删除索引2的元素 // 遍历 foreach (var fruit in fruits) { Console.WriteLine(fruit); // 苹果、葡萄、芒果 } ``` | 1. 需要索引访问和动态修改的集合场景;2. 统一列表类的操作接口(如自定义列表实现);3. 既需要遍历又需要增删改的业务场景;4. 方法参数中限制集合为列表类型(保证索引功能) | 1. 核心功能:索引访问、添加、删除、插入、查找索引;2. 继承关系:IList<T> → ICollection<T> → IEnumerable<T>;3. 常用实现类:List<T>、ArrayList(非泛型,不推荐);4. 比ICollection<T>多了索引相关操作,比数组多了动态增删功能 |
| implicit | 隐式转换运算符,用于自定义类型的自动类型转换(无需手动指定) | csharp public class Centimeter { public double Value { get; set; } public static implicit operator Meter(Centimeter cm) { return new Meter { Value = cm.Value / 100 }; } } Centimeter cm = new(){ Value = 200 }; Meter m = cm; // 隐式转换 | 1. 安全的类型转换(无精度丢失、数据溢出);2. 简化常用转换场景;3. 自定义类型与基础类型的兼容转换 | 1. 转换无需手动干预,编译器自动完成;2. 必须确保转换安全(否则用explicit);3. 与explicit不能同时重载同一转换方向;4. 可提高代码简洁性 |
| in | 1. 泛型协变修饰符(C# 7.2+);2. 方法参数输入修饰符(按只读引用传递) | csharp // 泛型协变 interface IReadOnlyList<<in T> { T GetItem(int index); } // 输入参数 public void Print(in int value) { // value = 10; // 报错,只读 } int num = 5; Print(num); | 1. 泛型接口协变(如IEnumerable<out T>的反向场景);2. 大型值类型参数传递(避免拷贝) | 1. in参数只读,不能修改;2. 泛型in表示输入类型(只能作为参数);3. 与out协变修饰符相反 |
| Index/Range | 索引和范围类型(System.Index/System.Range,C# 8.0+),Index表示集合/数组的索引(支持从末尾倒数),Range表示集合/数组的一个范围,简化切片操作语法 | ```csharp // 1. Index使用(索引表示) int[] arr = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; // 正向索引(从0开始) Index index1 = new Index(2); // 索引2(第三个元素) Console.WriteLine(arr[index1]); // 3 // 反向索引(从末尾开始,^1表示最后一个元素) Index index2 = ^1; // 等价于new Index(1, fromEnd: true) Console.WriteLine(arr[index2]); // 8 Index index3 = ^3; // 倒数第三个元素 Console.WriteLine(arr[index3]); // 6 // 2. Range使用(范围表示,左闭右开) // 范围:从索引1到索引4(不包含4) Range range1 = 1..4; int[] slice1 = arr[range1]; Console.WriteLine(string.Join(",", slice1)); // 2,3,4 // 范围:从开头到索引3(不包含3) Range range2 = ..3; int[] slice2 = arr[range2]; Console.WriteLine(string.Join(",", slice2)); // 1,2,3 // 范围:从索引5到末尾 Range range3 = 5..; int[] slice3 = arr[range3]; Console.WriteLine(string.Join(",", slice3)); // 6,7,8 // 范围:倒数第四个到倒数第二个(不包含倒数第二个) Range range4 = ^4..^2; int[] slice4 = arr[range4]; Console.WriteLine(string.Join(",", slice4)); // 5,6 // 3. 字符串切片(配合ReadOnlySpan<char>) string str = "Hello C# World"; Range strRange = 6..11; // 从索引6到11(不包含11) string subStr = str[strRange]; Console.WriteLine(subStr); // C# Wor // 4. List切片(C# 8.0+支持) List<string> fruits = new List<string> { "苹果", "香蕉", "橙子", "芒果" }; Range fruitRange = 1..3; List<string> subFruits = fruits.GetRange(fruitRange.Start.Value, fruitRange.End.Value - fruitRange.Start.Value); Console.WriteLine(string.Join(",", subFruits)); // 香蕉,橙子 ``` | 1. 数组、字符串、List等集合的切片操作;2. 简化从末尾倒数的索引访问(无需计算长度);3. 清晰的范围表示(提高代码可读性);4. 配合Span<T>/Memory<T>进行内存切片 | 1. Index语法:n(正向索引,n为非负整数)、^n(反向索引,n为正整数,^1表示最后一个元素);2. Range语法:start..end(左闭右开区间,包含start索引,不包含end索引),支持省略start(..end,从开头开始)或end(start..,到末尾结束);3. 适用类型:数组、字符串、Span<T>、Memory<T>、List<T>(需通过GetRange间接支持)等;4. 性能:Range切片操作对于数组、Span<T>等类型是无内存复制的(直接引用原数据),对于字符串会创建新字符串;5. 注意事项:Range的start索引必须小于等于end索引,否则会抛出ArgumentOutOfRangeException;6. 与Slice方法的关系:Range切片是Slice方法的语法糖(如arr[a..b]等价于arr.AsSpan().Slice(a, b-a).ToArray()) |
| Init-only Properties | 仅初始化属性(C# 9.0+),属性的set访问器替换为init访问器,允许属性仅在对象初始化时(对象创建时或解构时)赋值,之后无法修改,实现对象不可变性 | ```csharp // 1. 类中定义init-only属性 public class Product { public int Id { get; init; } // init-only属性 public string Name { get; init; } public decimal Price { get; init; } } // 2. 初始化时赋值(支持对象初始化器) Product p1 = new Product { Id = 1, Name = "手机", Price = 2999.99m }; // 3. 构造函数中赋值 public class Product2 { public int Id { get; init; } public string Name { get; init; } public Product2(int id, string name) { Id = id; // 构造函数中可赋值 Name = name; } } Product2 p2 = new Product2(2, "电脑"); // 4. 初始化后无法修改 // p1.Id = 3; // 报错,init-only属性初始化后不可修改 // 5. 记录类型中的init-only属性(默认) public record Person { public string Name { get; init; } public int Age { get; init; } } Person person = new Person { Name = "张三", Age = 28 }; // person.Name = "李四"; // 报错 ``` | 1. 不可变对象的属性定义(如DTO、实体类);2. 确保对象初始化后状态不被修改(线程安全);3. 记录类型(Record)的属性默认使用init访问器;4. 需要严格控制属性修改时机的场景 | 1. 语法:public T Prop { get; init; };2. 赋值时机:对象初始化器、构造函数、解构方法;3. 初始化后修改会编译报错;4. 与readonly字段的区别:readonly字段仅在声明或构造函数中赋值,init-only属性支持对象初始化器赋值,更灵活;5. 支持自动实现属性和手动实现属性(get和init访问器) |
| int | 32位有符号值类型(System.Int32),表示整数,范围-2¹⁴⁷⁴⁸³⁶⁴⁸~2¹⁴⁷⁴⁸³⁶⁴⁷ | csharp int age = 25; int sum = 10 + 20; | 存储整数型数据(年龄、分数、数量等),日常开发最常用数值类型 | 1. 默认值为0;2. 超出范围会发生溢出(需用checked关键字检测);3. 与uint(无符号)互斥 |
| interface | 定义方法、属性、事件的契约(无实现),用于多态和代码解耦 | csharp interface IAnimal { void Eat(); string Name { get; } } class Dog : IAnimal { public void Eat() => Console.WriteLine("吃骨头"); public string Name => "狗"; } | 1. 多继承场景(C#类单继承,接口多实现);2. 定义模块间通信契约;3. 依赖注入 | 1. 成员默认public(不可显式修饰);2. 不能包含字段和构造函数;3. 接口可继承接口,类需实现所有成员 |
| Interlocked | 原子操作类(System.Threading.Interlocked),提供对共享变量的原子操作(自增、自减、赋值、比较交换),无需显式锁定 | ```csharp private int _counter; private long _total; // 原子自增(等价于lock后的_counter++) public int IncrementCounter() { return Interlocked.Increment(ref _counter); } // 原子自减 public int DecrementCounter() { return Interlocked.Decrement(ref _counter); } // 原子赋值(将newValue赋值给_total,返回旧值) public long SetTotal(long newValue) { return Interlocked.Exchange(ref _total, newValue); } // 比较交换(CAS):如果_current等于expected,则赋值为newValue,返回旧值 private int _current = 0; public bool CompareAndSwap(int expected, int newValue) { return Interlocked.CompareExchange(ref _current, newValue, expected) == expected; } ``` | 1. 简单共享变量的线程安全操作(计数器、标志位);2. 高性能同步场景(避免lock的开销);3. 无锁编程(基于CAS操作实现线程安全);4. 原子赋值和比较交换场景 | 1. 支持int、long、float、double、object等类型;2. 操作是原子的,不会被线程调度中断;3. 性能优于lock(无锁开销),但仅适用于简单变量操作;4. 复杂逻辑仍需使用lock或其他同步机制;5. CompareExchange是无锁编程的核心操作 |
| IQueryable<> | 泛型查询接口(System.Linq.IQueryable<T>),继承自IEnumerable<T>,封装了查询表达式(Expression<Func<T, bool>>),支持延迟执行和远程查询(如数据库查询) | ```csharp // 以EF Core为例(IQueryable<T>的典型应用) using (var dbContext = new MyDbContext()) { // 获取IQueryable<T>查询对象(未执行查询) IQueryable<User> usersQuery = dbContext.Users .Where(u => u.Age > 18) // 构建查询表达式 .OrderBy(u => u.CreateTime); // 解析查询表达式(可选) Expression expression = usersQuery.Expression; Console.WriteLine("查询表达式:" + expression); // 执行查询(遍历、ToList、Count等操作触发执行) List<User> adultUsers = usersQuery.ToList(); // 此时才向数据库发送SQL // 动态构建查询条件 int minAge = 20; if (minAge > 18) { usersQuery = usersQuery.Where(u => u.Age >= minAge); // 追加查询条件 } var filteredUsers = usersQuery.ToList(); // 执行追加后的查询 } // 自定义IQueryable<T>(简化示例) public class MyQueryable<T> : IQueryable<T> { public Expression Expression { get; } public Type ElementType => typeof(T); public IQueryProvider Provider { get; } public IEnumerator<T> GetEnumerator() => Provider.Execute<IEnumerable<T>>(Expression).GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } ``` | 1. 数据库查询(如EF Core、Linq to SQL);2. 远程数据查询(如Web API查询、分布式查询);3. 延迟执行的复杂查询构建;4. 动态组合查询条件的场景 | 1. 核心特性:延迟执行(查询在触发枚举时才执行)、查询表达式树(可被查询提供器解析);2. 继承关系:IQueryable<T> → IEnumerable<T>;3. 查询提供器(IQueryProvider)负责解析表达式树并执行查询(如EF Core将表达式树转换为SQL);4. 与IEnumerable<T>的区别:IEnumerable<T>在本地内存执行查询,IQueryable<T>支持远程查询;5. 常用触发查询执行的方法:ToList()、ToArray()、Count()、FirstOrDefault()、foreach遍历等 |
| IQueryProvider | 查询提供器接口(System.Linq.IQueryProvider),定义了解析和执行IQueryable<T>查询表达式的方法,是IQueryable<T>的核心驱动组件 | ```csharp // 实现自定义IQueryProvider public class MyQueryProvider : IQueryProvider { // 执行返回IEnumerable<TResult>的查询 public IQueryable<TResult> CreateQuery<TResult>(Expression expression) { return new MyQueryable<TResult>(this, expression); } // 执行返回单个值的查询 public IQueryable CreateQuery(Expression expression) { Type elementType = expression.Type.GetGenericArguments()[0]; return (IQueryable)Activator.CreateInstance( typeof(MyQueryable<>).MakeGenericType(elementType), this, expression); } // 执行返回单个值的查询 public TResult Execute<TResult>(Expression expression) { // 解析表达式树,执行查询逻辑(如转换为自定义查询语言) Console.WriteLine("解析查询表达式:" + expression); // 模拟执行查询并返回结果 if (typeof(TResult).IsGenericType && typeof(TResult).GetGenericTypeDefinition() == typeof(IEnumerable<>)) { return (TResult)(object)new List<int> { 1, 2, 3 }; // 模拟结果 } return default; } // 非泛型Execute方法 public object Execute(Expression expression) { Type resultType = expression.Type; MethodInfo executeMethod = typeof(MyQueryProvider) .GetMethod("Execute", new[] { typeof(Expression) }) .MakeGenericMethod(resultType); return executeMethod.Invoke(this, new object[] { expression }); } } // 配套的IQueryable实现 public class MyQueryable<T> : IQueryable<T> { public IQueryProvider Provider { get; } public Expression Expression { get; } public Type ElementType => typeof(T); public MyQueryable(MyQueryProvider provider, Expression expression) { Provider = provider; Expression = expression ?? Expression.Constant(this); } public IEnumerator<T> GetEnumerator() { return Provider.Execute<IEnumerable<T>>(Expression).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } // 使用自定义查询提供器 var provider = new MyQueryProvider(); IQueryable<int> query = provider.CreateQuery<int>(Expression.Constant(new List<int> { 1, 2, 3 })); var result = query.ToList(); // 触发Provider.Execute执行 ``` | 1. 自定义查询框架开发(如自定义ORM、特定数据源查询);2. 解析IQueryable<T>查询表达式并转换为目标查询语言(如SQL、NoSQL查询语句);3. 扩展IQueryable<T>的查询能力;4. 远程数据查询的适配(如将查询表达式转换为API请求参数) | 1. 核心方法:CreateQuery()(创建IQueryable查询对象)、Execute()(执行查询表达式并返回结果);2. 负责将IQueryable<T>的表达式树解析为可执行的查询逻辑(如SQL生成);3. 是连接IQueryable<T>和实际数据源的桥梁;4. 自定义查询提供器需配合IQueryable<T>实现使用;5. EF Core、Linq to SQL等框架均内置了对应的IQueryProvider实现 |
| is | 类型判断运算符,检查对象是否为指定类型或兼容类型,返回bool值 | csharp object obj = "Hello"; bool isString = obj is string; bool isInt = obj is int; // false if (obj is string str) { Console.WriteLine(str.Length); // 模式匹配,直接使用str } | 1. 类型检查(如多态场景判断子类类型);2. 安全的类型转换前校验;3. 模式匹配(C# 7.0+) | 1. 不会抛出异常(null检查返回false);2. 支持模式匹配(如is string str直接声明变量);3. 检查引用类型时考虑继承关系(子类实例is父类为true);4. 与as运算符配合使用(先判断后转换) |
| Lambda Expressions(补充高级用法) | Lambda表达式(补充高级用法),除基础语法外,支持闭包、表达式树、多语句、泛型等高级特性,是LINQ、委托的核心语法糖 | ```csharp // 1. 闭包(捕获外部变量) int factor = 2; Func<int, int> multiply = x => x * factor; Console.WriteLine(multiply(5)); // 10(捕获factor变量) factor = 3; Console.WriteLine(multiply(5)); // 15(闭包捕获的是变量引用,而非值) // 2. 表达式树(将Lambda转换为表达式树,可解析) Expression<Func<int, int, int>> addExpr = (a, b) => a + b; // 解析表达式树 BinaryExpression body = (BinaryExpression)addExpr.Body; Console.WriteLine($"表达式:{body.Left} {body.NodeType} {body.Right}"); // x Add y // 3. 多语句Lambda(带{}和return) Func<int, bool> isEven = x => { if (x % 2 == 0) { return true; } return false; }; // 4. 泛型Lambda(C# 10.0+) var identity = (T value) => value; // 泛型Lambda,自动推断类型 int intVal = identity(10); string strVal = identity("hello"); // 5. Lambda作为方法参数(LINQ示例) List<int> numbers = new List<int> { 1, 2, 3, 4, 5 }; var evenNumbers = numbers.Where(n => n % 2 == 0); // Lambda作为Where方法参数 foreach (var num in evenNumbers) { Console.WriteLine(num); // 2、4 } ``` | 1. 闭包:捕获外部变量的场景(如动态条件过滤);2. 表达式树:需要解析Lambda逻辑的场景(如ORM框架的SQL生成);3. 复杂逻辑的委托/事件赋值;4. LINQ查询中的条件过滤、投影、排序等 | 1. 闭包注意事项:捕获的是变量引用,而非值,外部变量修改会影响Lambda执行结果;2. 表达式树与委托的区别:表达式树可解析为抽象语法树(AST),委托是方法指针;3. 多语句Lambda必须包含{}和return(有返回值时);4. 泛型Lambda无需显式声明泛型参数,编译器自动推断;5. Lambda表达式在编译时会被转换为匿名方法或表达式树(取决于上下文) |
| Lazy<T> | 延迟初始化类(System.Lazy<T>),泛型类,用于延迟对象的创建,直到第一次访问Value属性时才初始化,提高程序启动性能 | ```csharp // 1. 基础延迟初始化(无参数构造函数) Lazy<string> lazyStr = new Lazy<string>(() => { Console.WriteLine("初始化字符串..."); return "Hello Lazy"; }); Console.WriteLine("未访问Value,未初始化"); string str = lazyStr.Value; // 第一次访问,触发初始化 Console.WriteLine(str); string str2 = lazyStr.Value; // 再次访问,使用已初始化的实例(不重复执行初始化逻辑) // 2. 带参数的初始化 Lazy<Person> lazyPerson = new Lazy<Person>(() => new Person("张三", 28)); Person person = lazyPerson.Value; // 初始化Person实例 // 3. 线程安全配置(默认线程安全) // 线程安全模式:LazyThreadSafetyMode.ExecutionAndPublication(默认,确保只初始化一次) Lazy<int> lazyInt = new Lazy<int>(() => { Thread.Sleep(100); return new Random().Next(100); }, LazyThreadSafetyMode.ExecutionAndPublication); // 多线程访问 Parallel.For(0, 5, _ => { Console.WriteLine(lazyInt.Value); // 所有线程获取到同一个值(仅初始化一次) }); ``` | 1. 重量级对象的延迟创建(如数据库连接、大集合、复杂服务实例);2. 提高程序启动速度(避免启动时初始化所有对象);3. 条件性创建对象(可能不会用到的对象);4. 线程安全的延迟初始化场景 | 1. 核心特性:延迟初始化、线程安全(可配置)、只初始化一次(默认);2. 初始化逻辑通过委托传入(如Lambda表达式);3. 线程安全模式:LazyThreadSafetyMode.ExecutionAndPublication(默认,线程安全)、LazyThreadSafetyMode.None(非线程安全,性能更高)、LazyThreadSafetyMode.PublicationOnly(允许多次初始化,但只使用第一个成功的实例);4. 可通过IsValueCreated属性判断对象是否已初始化;5. 初始化失败后,再次访问Value会重新抛出异常 |
| LazyInitializer | 延迟初始化工具类(System.Threading.LazyInitializer),静态类,提供静态方法实现对象的延迟初始化,无需创建Lazy<T>实例,支持更灵活的延迟初始化控制(如条件初始化、非泛型类型) | ```csharp // 1. 基础延迟初始化(确保对象仅初始化一次) object lazyObj = null; bool initialized = false; // EnsureInitialized:确保对象已初始化,仅执行一次初始化逻辑 LazyInitializer.EnsureInitialized(ref lazyObj, ref initialized, () => { Console.WriteLine("初始化lazyObj..."); return new object(); }); // 再次调用,不会重复初始化 LazyInitializer.EnsureInitialized(ref lazyObj, ref initialized, () => { Console.WriteLine("再次初始化lazyObj..."); // 不会执行 return new object(); }); Console.WriteLine($"lazyObj是否初始化:{lazyObj != null}"); // True // 2. 泛型版本(类型安全) string lazyStr = null; LazyInitializer.EnsureInitialized(ref lazyStr, () => { Console.WriteLine("初始化lazyStr..."); return "Hello LazyInitializer"; }); Console.WriteLine($"lazyStr的值:{lazyStr}"); // Hello LazyInitializer // 3. 条件延迟初始化(根据条件决定是否初始化) int? lazyInt = null; if (someCondition()) // 自定义条件 { LazyInitializer.EnsureInitialized(ref lazyInt, () => 100); } // 4. 多线程安全的延迟初始化(默认线程安全) object threadSafeObj = null; bool threadSafeInitialized = false; Parallel.For(0, 5, _ => { LazyInitializer.EnsureInitialized(ref threadSafeObj, ref threadSafeInitialized, () => { Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}初始化threadSafeObj..."); Thread.Sleep(100); // 模拟耗时初始化 return new object(); }); }); // 输出:仅一个线程执行初始化逻辑 // 5. 非泛型类型的延迟初始化 MyNonGenericClass nonGenericObj = null; LazyInitializer.EnsureInitialized(ref nonGenericObj, () => new MyNonGenericClass()); Console.WriteLine($"非泛型对象是否初始化:{nonGenericObj != null}"); // True // 6. 初始化带参数的对象 Person lazyPerson = null; LazyInitializer.EnsureInitialized(ref lazyPerson, () => new Person("张三", 28)); Console.WriteLine($"延迟初始化的Person:{lazyPerson}"); // 张三(28岁) // 辅助类和方法 public class MyNonGenericClass { } public class Person { public string Name { get; } public int Age { get; } public Person(string name, int age) { Name = name; Age = age; } public override string ToString() { return $"{Name}({Age}岁)"; } } bool someCondition() { // 模拟条件判断 return true; } ``` | 1. 无需Lazy<T>实例的延迟初始化场景;2. 条件性延迟初始化(根据自定义条件决定是否初始化);3. 非泛型类型的延迟初始化;4. 更灵活的初始化控制(如手动管理初始化状态);5. 低开销的延迟初始化(避免Lazy<T>的对象分配) | 1. 核心方法:EnsureInitialized()(重载多个版本,支持泛型/非泛型、带初始化状态标记、线程安全控制);2. 线程安全:默认是线程安全的(通过锁确保仅初始化一次),也可通过参数控制锁的使用;3. 与Lazy<T>的区别:Lazy<T>是封装好的延迟初始化类(需创建实例),LazyInitializer是静态工具类(无需创建实例,更灵活);4. 初始化状态:可通过ref bool参数手动管理初始化状态(如标记对象是否已初始化);5. 适用场景:适合简单的延迟初始化场景,或需要手动控制初始化状态的场景;复杂场景(如线程安全模式配置)仍推荐使用Lazy<T>;6. 性能:与Lazy<T>性能相当,在简单场景下开销略低(无需创建Lazy<T>实例);7. 注意事项:EnsureInitialized()的第一个参数必须是ref参数(确保修改的是原变量),初始化工厂方法仅执行一次 |
| lock | 线程同步关键字,确保代码块同一时间只有一个线程执行,避免并发冲突 | csharp private readonly object _lockObj = new(); public void UpdateData() { lock (_lockObj) { // 临界区代码(如修改共享变量、操作数据库) } } | 多线程环境下操作共享资源(全局变量、文件、数据库),解决线程安全问题 | 1. 锁定对象必须是引用类型(推荐用private readonly对象,避免被修改);2. 不能锁定值类型(会装箱,每次锁定不同对象);3. 内部封装Monitor.Enter()和Monitor.Exit() |
| lock(补充细节版) | 线程同步关键字,用于确保临界区代码同一时间只能被一个线程执行,底层封装了Monitor.Enter和Monitor.Exit方法,自动处理异常 | ```csharp public class Counter { // 锁定对象:必须是private readonly引用类型,避免被外部修改 private readonly object _lockObj = new(); private int _count; public int Increment() { // 临界区:确保count自增的原子性 lock (_lockObj) { _count++; return _count; } } public int GetCount() { lock (_lockObj) { return _count; } } } // 多线程调用 var counter = new Counter(); Parallel.For(0, 1000, _ => counter.Increment()); Console.WriteLine(counter.GetCount()); // 1000(线程安全) ``` | 1. 多线程环境下操作共享资源(全局变量、静态字段、数据库连接);2. 避免并发修改导致的数据不一致(如计数器、缓存);3. 实现线程安全的单例模式 | 1. 锁定对象必须是引用类型(值类型会装箱,每次锁定不同对象,失去同步效果);2. 推荐使用private readonly object作为锁定对象,避免锁定this(外部可访问)或Type对象(全局共享);3. lock块内部避免长时间阻塞(影响性能);4. 自动处理异常:即使临界区抛出异常,也会自动调用Monitor.Exit释放锁 |
| long | 64位有符号值类型(System.Int64),范围-9223372036854775808~9223372036854775807 | csharp long bigNumber = 9223372036854775807L; // 需加L后缀 long timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds(); | 1. 存储大整数(时间戳、ID、大数据量计数);2. 避免int溢出的场景 | 1. 默认值为0;2. 常量需加L后缀(否则视为int);3. 与ulong(无符号长整数)互补;4. 性能与int接近,适合大数值计算 |
| Match/MatchCollection | 正则匹配结果类(System.Text.RegularExpressions.Match/MatchCollection),Match表示单个正则匹配结果,MatchCollection表示多个匹配结果的集合 | ```csharp string str = "用户1:张三,年龄28;用户2:李四,年龄22;用户3:王五,年龄30"; string pattern = @"用户(\d+):([^,]+),年龄(\d+)"; // 获取所有匹配项(MatchCollection) MatchCollection matches = Regex.Matches(str, pattern); Console.WriteLine($"匹配到{matches.Count}个用户"); // 遍历匹配结果 foreach (Match match in matches) { // 获取整个匹配项 Console.WriteLine("完整匹配:" + match.Value); // 获取分组(括号中的内容) string userNo = match.Groups[1].Value; // 分组1:用户编号 string userName = match.Groups[2].Value; // 分组2:用户名 string age = match.Groups[3].Value; // 分组3:年龄 Console.WriteLine($"用户{userNo}:{userName},年龄{age}"); // 获取匹配位置和长度 Console.WriteLine($"匹配起始位置:{match.Index},长度:{match.Length}"); } // 获取单个匹配项 Match firstMatch = Regex.Match(str, pattern); if (firstMatch.Success) { Console.WriteLine("第一个匹配项:" + firstMatch.Value); } ``` | 1. 正则匹配后的结果提取(如分组数据提取);2. 遍历多个匹配结果;3. 获取匹配项的位置、长度等信息;4. 验证正则匹配是否成功 | 1. Match核心成员:Success(是否匹配成功)、Value(匹配的字符串)、Index(匹配起始位置)、Length(匹配长度)、Groups(分组集合);2. MatchCollection是延迟加载的集合,遍历时时才获取匹配结果;3. Groups[0]表示整个匹配项,Groups[1]及以后表示正则表达式中括号定义的分组;4. 可通过Match.NextMatch()获取下一个匹配项(替代foreach遍历);5. 若匹配失败,Match.Success为false,Value为空字符串 |
| Monitor | 线程同步类(System.Threading.Monitor),提供与lock类似的同步功能,支持更精细的控制(如超时、尝试获取锁) | ```csharp private readonly object _lockObj = new(); private int _data; public void UpdateData(int newValue) { // 尝试获取锁,超时时间500ms if (Monitor.TryEnter(_lockObj, 500)) { try { // 临界区 _data = newValue; Console.WriteLine($"数据更新为:{_data}"); } finally { // 必须手动释放锁 Monitor.Exit(_lockObj); } } else { Console.WriteLine("获取锁超时,无法更新数据"); } } ``` | 1. 需要超时控制的同步场景(避免无限等待);2. 尝试获取锁而不阻塞的场景;3. 更精细的线程同步控制(如脉冲通知);4. 替代lock实现复杂同步逻辑 | 1. lock关键字是Monitor.Enter和Monitor.Exit的语法糖,但Monitor支持更多功能;2. 必须在finally块中调用Monitor.Exit释放锁,避免异常导致锁泄漏;3. 支持Monitor.Pulse()/Monitor.PulseAll()唤醒等待线程;4. Monitor.Wait()让线程释放锁并等待唤醒 |
| null | 空引用标识符,表示引用类型未指向任何对象,可空值类型无有效值 | csharp string name = null; Person person = null; int? score = null; bool isNull = name == null; | 1. 初始化引用类型变量(表示无数据);2. 标记可空值类型无值;3. 条件判断(检查对象是否初始化) | 1. 不能赋值给非可空值类型(如int num = null报错);2. 引用类型默认值为null;3. null与任何值比较(除==和!=)均返回false;4. C# 8.0+支持nullable reference types(NRT),需显式声明可空引用类型(string?) |
| Nullable Reference Types(NRT) | 可空引用类型(C# 8.0+),语法特性,通过在引用类型后添加“?”(如string?)声明可空引用类型,编译器会进行空引用静态检查,减少空引用异常(NullReferenceException) | ```csharp // 启用可空引用类型(项目文件中或代码文件顶部) #nullable enable // 1. 可空引用类型声明 string? nullableStr = null; // 允许为null string nonNullableStr = "Hello"; // 不允许为null(编译器检查) // 2. 编译器空检查 // nonNullableStr = null; // 编译警告:不能将null赋值给非可空引用类型 // 3. 空值传播和空合并 int? length = nullableStr?.Length; // 空值传播,length为null string safeStr = nullableStr ?? "默认值"; // 空合并,safeStr为"默认值" // 4. 非空断言(告诉编译器该变量不会为null,谨慎使用) string? strWithValue = "Hello"; int strLength = strWithValue!.Length; // !为非空断言,若strWithValue为null会抛异常 // 5. 方法参数和返回值 // 可空参数 void PrintName(string? name) { Console.WriteLine(name ?? "未知名称"); } // 非可空返回值(编译器确保不会返回null) string GetNonNullName() { return "张三"; // return null; // 编译警告:不能返回null给非可空引用类型 } // 6. 可空引用类型数组 string?[] nullableStrArray = new string?[3]; nullableStrArray[0] = null; nullableStrArray[1] = "李四"; // 7. 禁用特定代码段的空检查 #nullable disable string temp = null; // 无警告 #nullable restore // 调用方法 PrintName(null); // 允许 string name = GetNonNullName(); Console.WriteLine(name.Length); // 安全,无空引用异常 ``` | 1. 减少空引用异常(提高代码健壮性);2. 明确引用类型的可空性(提高代码可读性);3. 编译器静态空检查(在编译时发现潜在空引用问题);4. 旧项目逐步迁移(通过#nullable指令局部启用) | 1. 启用方式:项目文件中设置<Nullable>enable</Nullable>,或代码文件顶部添加#nullable enable;2. 核心语法:T?(可空引用类型)、T(非可空引用类型)、!(非空断言)、?.(空值传播)、??(空合并);3. 编译器行为:对非可空引用类型的赋值、返回值进行空检查,发出警告;4. 注意事项:非空断言(!)会压制编译器警告,若实际为null会运行时抛异常,谨慎使用;5. 与可空值类型的区别:可空引用类型是语法特性(编译器检查),可空值类型是Nullable<T>结构体(运行时支持);6. 适用场景:新开发项目建议全面启用,旧项目可局部启用逐步迁移 |
| Nullable<T> | 可空值类型(System.Nullable<T>),泛型结构,用于让值类型能够存储null值,T必须是不可为null的值类型(如int、DateTime),语法糖为“T?” | ```csharp // 两种等价声明方式 Nullable<int> score1 = null; int? score2 = null; // 赋值非null值 score2 = 95; // 判断是否有值 if (score1.HasValue) { Console.WriteLine(score1.Value); } else { Console.WriteLine("score1无值"); } // 空合并运算符赋值默认值 int finalScore = score1 ?? 60; // 60(score1为null时使用默认值) // 安全访问Value(C# 7.0+) if (score2 is int s) { Console.WriteLine($"score2的值:{s}"); } // 可空值类型数组 int?[] scores = new int?[] { 85, null, 92, 78 }; ``` | 1. 存储可能为空的数据(如数据库查询结果中的可选字段);2. 表单输入字段(如可选的年龄、分数);3. 方法返回值(表示操作失败或无结果);4. 避免使用魔法值(如用null表示“未设置”,而非-1) | 1. 核心成员:HasValue(是否有值)、Value(获取实际值,无值时抛InvalidOperationException);2. 语法糖“T?”等价于Nullable<T>,推荐使用语法糖;3. 不可嵌套(如Nullable<Nullable<int>>不允许);4. 可空值类型之间、可空与非可空值类型之间支持隐式转换(非空→可空自动转换,可空→非空需显式转换或判空);5. 支持算术运算、比较运算(含null参与的运算,结果遵循null传播规则) |
| object | 所有类型的基类(System.Object),引用类型,可存储任意类型的值 | csharp object obj1 = 10; // 值类型装箱 object obj2 = "Hello"; // 引用类型 object obj3 = new Person(); Console.WriteLine(obj1.GetType()); // System.Int32 | 1. 存储任意类型数据(如集合中混合类型);2. 反射操作(如获取类型信息);3. 兼容旧代码(非泛型场景) | 1. 值类型赋值给object会发生装箱,反之拆箱(需显式转换);2. 提供ToString()、Equals()、GetHashCode()等基础方法;3. 可空引用类型为object?;4. 泛型出现后,推荐使用泛型替代object(避免装箱拆箱开销) |
| operator | 运算符重载关键字,允许为自定义类型(class/struct)重定义标准运算符 | csharp public struct Vector2 { public int X { get; set; } public int Y { get; set; } public static Vector2 operator +(Vector2 a, Vector2 b) { return new Vector2 { X = a.X + b.X, Y = a.Y + b.Y }; } } Vector2 v1 = new(){ X=1, Y=2 }; Vector2 v2 = new(){ X=3, Y=4 }; Vector2 v3 = v1 + v2; // (4,6) | 1. 自定义类型的数学运算(向量、矩阵、复数);2. 简化自定义类型的比较、转换;3. 提高代码可读性 | 1. 可重载一元运算符(+、-、!)和二元运算符(+、-、*、==、!=等);2. 重载运算符必须是public static;3. ==和!=需成对重载;4. 不能重载sizeof、is等运算符 |
| Operator Overloading(运算符重载) | C#特性,允许为自定义值类型或引用类型重定义预定义运算符(如算术运算符、比较运算符等),使自定义类型可像内置类型一样直接使用运算符,简化代码逻辑并提升可读性 | ```csharp // 1. 自定义数值类型并重载算术运算符 public struct Point { public int X { get; } public int Y { get; } public Point(int x, int y) { X = x; Y = y; } // 重载+运算符(点的相加) public static Point operator +(Point p1, Point p2) { return new Point(p1.X + p2.X, p1.Y + p2.Y); } // 重载-运算符(点的相减) public static Point operator -(Point p1, Point p2) { return new Point(p1.X - p2.X, p1.Y - p2.Y); } // 重载==和!=运算符(值相等性判断) public static bool operator ==(Point p1, Point p2) { return p1.X == p2.X && p1.Y == p2.Y; } public static bool operator !=(Point p1, Point p2) { return !(p1 == p2); } // 重写Equals和GetHashCode(配合==运算符) public override bool Equals(object obj) { return obj is Point point && this == point; } public override int GetHashCode() { return HashCode.Combine(X, Y); } public override string ToString() { return $"({X}, {Y})"; } } // 使用重载运算符的自定义类型 Point p1 = new Point(1, 2); Point p2 = new Point(3, 4); Point sum = p1 + p2; Console.WriteLine($"p1 + p2 = {sum}"); // (4, 6) Point diff = p1 - p2; Console.WriteLine($"p1 - p2 = {diff}"); // (-2, -2) Console.WriteLine($"p1 == p2 ? {p1 == p2}"); // False Console.WriteLine($"p1 != p2 ? {p1 != p2}"); // True // 2. 重载比较运算符(需实现IComparable<T>) public struct Temperature : IComparable<Temperature> { public decimal Value { get; } public Temperature(decimal value) { Value = value; } // 重载>运算符 public static bool operator >(Temperature t1, Temperature t2) { return t1.Value > t2.Value; } // 重载<运算符 public static bool operator<(Temperature t1, Temperature t2) { return t1.Value < t2.Value; } // 实现IComparable<T>接口 public int CompareTo(Temperature other) { return Value.CompareTo(other.Value); } } Temperature t1 = new Temperature(25.5m); Temperature t2 = new Temperature(30.2m); Console.WriteLine($"t1 > t2 ? {t1 > t2}"); // False Console.WriteLine($"t1 < t2 ? {t1 < t2}"); // True ``` | 1. 自定义数值/几何类型(如Point、Vector、Temperature);2. 需简化运算逻辑的业务对象(如金额、数量);3. 需值相等性判断的自定义类型;4. 提升代码可读性(用运算符替代专用方法,如Add()) | 1. 可重载运算符:算术运算符(+、-、*、/等)、比较运算符(==、!=、<、>等)、位运算符(&、|、^等),赋值运算符(+=、-=等)会自动继承对应的运算符逻辑;2. 重载规则:运算符必须是static,参数至少有一个是当前自定义类型;3. 配对要求:==与!=必须成对重载,<与>必须成对重载;4. 配套重写:重载==后需重写Equals()和GetHashCode(),确保一致性;5. 限制:不能重载=、.、?:、sizeof等运算符;不能创建新运算符,只能重定义已有运算符;6. 引用类型重载:引用类型重载==默认比较引用,重载后可改为值比较,但需谨慎(避免与默认行为冲突) |
| out | 1. 泛型协变修饰符;2. 方法参数输出修饰符(按引用传递,无需初始化) | csharp // 输出参数 public bool TryParseInt(string input, out int result) { return int.TryParse(input, out result); } // 调用 if (TryParseInt("123", out int num)) Console.WriteLine(num); | 方法返回多个结果(如解析成功状态+结果)、泛型接口协变(如Action<out T>) | 1. out参数无需初始化即可传入;2. 方法必须为out参数赋值;3. C# 7.0+支持out变量 inline声明 |
| override | 重写修饰符,用于子类重写基类的virtual/abstract方法 | csharp class Bird : Animal { public override void MakeSound() => Console.WriteLine("叽叽叫"); } Animal bird = new Bird(); bird.MakeSound(); // 输出"叽叽叫" | 子类需要修改基类虚方法的实现,实现多态行为 | 1. 重写方法签名(参数、返回值)必须与基类一致;2. 重写后可被进一步密封(sealed override);3. 不能重写非虚方法 |
| params | 可变参数修饰符,允许方法接收任意数量的同类型参数,必须是最后一个参数 | csharp public int Sum(params int[] nums) { int total = 0; foreach (var num in nums) total += num; return total; } int result1 = Sum(1,2,3); int result2 = Sum(10,20,30,40); | 方法参数数量不固定的场景(如求和、字符串拼接、日志输出) | 1. 一个方法只能有一个params参数;2. 可直接传递数组或多个单独参数;3. 调用时若传null需显式指定(如Sum(null)) |
| partial | 部分类型/方法修饰符,允许将类、结构、接口、方法拆分到多个文件中定义 | csharp // File1.cs partial class Person { public string Name { get; set; } } // File2.cs partial class Person { public int Age { get; set; } public partial void ShowInfo(); } // File3.cs partial class Person { public partial void ShowInfo() { Console.WriteLine($"{Name}, {Age}"); } } | 1. 大型类拆分(多人协作、按功能拆分);2. 自动生成代码与手动编写代码分离(如EF Core实体、设计器生成代码);3. 部分方法(仅声明,在另一文件实现) | 1. 所有partial修饰的类型必须同名、同命名空间、同访问修饰符;2. 部分方法必须是void返回值、private访问级别;3. 若未实现部分方法,编译器会忽略调用;4. 不能用于密封类的部分方法 |
| Pattern Matching(模式匹配) | 模式匹配(C# 7.0+),是一种语法特性,用于检查值是否符合特定模式(如类型模式、常量模式、属性模式等),简化条件判断逻辑 | ```csharp // 1. 类型模式(判断类型并解构) object obj = new Person("张三", 28); if (obj is Person p) { Console.WriteLine($"姓名:{p.Name},年龄:{p.Age}"); } // 2. 常量模式(判断是否等于指定常量) int num = 5; if (num is 0) { Console.WriteLine("数字为0"); } else if (num is 5) { Console.WriteLine("数字为5"); } // 3. 属性模式(判断属性值) Person person = new Person("李四", 22); if (person is { Name: "李四", Age: < 30 }) { Console.WriteLine("李四,年龄小于30"); } // 4. 开关表达式中的模式匹配(C# 8.0+) string GetUserType(Person p) => p switch { { Age: < 18 } => "未成年人", { Age: >= 18 and <= 60 } => "成年人", { Age: > 60 } => "老年人", null => "未知用户", _ => "其他" }; Console.WriteLine(GetUserType(person)); // 成年人 // 5. 位置模式(匹配元组或解构后的字段) var point = (1, 2); string GetQuadrant((int X, int Y) p) => p switch { (0, 0) => "原点", (>, 0) => "第一象限", (<, 0) => "第三象限", (0, >) => "Y轴正方向", _ => "其他象限" }; Console.WriteLine(GetQuadrant(point)); // 第一象限 ``` | 1. 复杂类型判断和数据提取;2. 多条件分支判断(替代多层if-else);3. 开关表达式(switch expression)中的条件匹配;4. 元组、对象的字段/属性条件判断 | 1. 常用模式:类型模式(is Type var)、常量模式(is 常量)、属性模式(is { Prop: 条件 })、位置模式(is (x, y))、逻辑模式(and/or/not);2. 支持在if、switch、switch表达式中使用;3. 模式匹配是语法糖,简化了类型判断+强制转换+属性判断的组合逻辑;4. C# 10.0+支持关系模式(<、>、<=、>=)和逻辑模式的组合;5. 提高代码可读性和简洁性,减少模板代码 |
| Predicate<> | 泛型委托(System.Predicate),用于封装返回bool值的方法(判断条件),仅接收1个参数,返回bool | ```csharp // 判断整数是否为偶数 Predicate<int> isEven = x => x % 2 == 0; // 判断字符串是否为空或空白 Predicate<string> isNullOrWhiteSpace = s => string.IsNullOrWhiteSpace(s); // 结合List使用(筛选元素) List<int> numbers = new() { 1, 2, 3, 4, 5, 6 }; List<int> evenNumbers = numbers.FindAll(isEven); // 结果:[2,4,6] // 调用 Console.WriteLine(isEven(4)); // true Console.WriteLine(isNullOrWhiteSpace(" ")); // true ``` | 1. 数据筛选(List.Find、List.FindAll、Array.Find等方法的参数);2. 条件判断回调(如验证数据有效性);3. 简化返回bool值的单参数委托定义 | 1. 本质等价于Func<T, bool>;2. 仅支持1个参数,返回bool;3. 常用于集合的条件查询场景;4. .NET Framework中使用较多,.NET Core/.NET 5+中推荐直接使用Func<T, bool> |
| Queue<> | 泛型队列(System.Collections.Generic.Queue<T>),实现ICollection<T>,遵循先进先出(FIFO)原则,支持入队(添加尾部)和出队(移除头部)操作 | ```csharp // 初始化队列 Queue<string> taskQueue = new Queue<string>(); // 入队(添加到尾部) taskQueue.Enqueue("任务1"); taskQueue.Enqueue("任务2"); taskQueue.Enqueue("任务3"); // 查看头部元素(不删除) string firstTask = taskQueue.Peek(); // 任务1 // 出队(移除并返回头部元素) while (taskQueue.Count > 0) { string task = taskQueue.Dequeue(); Console.WriteLine($"执行任务:{task}"); // 依次执行任务1、2、3 } ``` | 1. 任务排队场景(如消息队列、任务调度);2. 先进先出的数据处理(如订单处理、请求排队);3. 缓存数据的先进先出淘汰策略;4. 广度优先搜索(BFS)算法实现 | 1. 核心操作:Enqueue(入队)、Dequeue(出队)、Peek(查看头部);2. 不支持索引访问,只能操作头部元素;3. 内部通过数组实现,容量不足时自动扩容;4. 线程不安全,多线程环境需使用ConcurrentQueue<T> |
| readonly | 只读修饰符,可修饰字段、索引器,字段只能在声明时或构造函数中初始化 | csharp public class Person { public readonly string Name; public readonly int Age = 18; // 声明时初始化 public Person(string name) { Name = name; // 构造函数中初始化 } } Person p = new("赵六"); // p.Name = "钱七"; // 报错,只读字段不能修改 | 1. 存储不可变数据(如配置项、常量值);2. 确保字段初始化后不被修改;3. 线程安全(只读字段初始化后无写操作) | 1. 修饰字段:值类型只读(不能修改值),引用类型只读(不能修改引用,但可修改对象内部成员);2. 可与static搭配(static readonly,静态只读字段);3. 静态只读字段只能在静态构造函数或声明时初始化;4. 与const的区别:const是编译时常量,readonly是运行时常量 |
| Record | 记录类型(C# 9.0+),引用类型,用于创建不可变的数据载体,默认实现值相等性判断,简化数据对象的定义(如DTO、实体类) | ```csharp // 1. 简单记录(位置参数) public record Person(string Name, int Age); // 2. 初始化记录 Person p1 = new Person("张三", 28); Person p2 = new Person("张三", 28); Person p3 = new Person("李四", 22); // 3. 值相等性判断(比较字段值,而非引用) Console.WriteLine(p1 == p2); // True(值相等) Console.WriteLine(p1 == p3); // False(值不相等) // 4. 不可变性(无法修改字段值,需用with表达式创建新实例) Person p4 = p1 with { Age = 29 }; // 复制p1,修改Age字段,创建新实例 Console.WriteLine(p4.Age); // 29 Console.WriteLine(p1.Age); // 28(原实例不变) // 5. 带属性和方法的记录 public record User { public string Name { get; init; } // init-only属性,仅初始化时可赋值 public int Age { get; init; } public string GetInfo() => $"姓名:{Name},年龄:{Age}"; } User u1 = new User { Name = "王五", Age = 30 }; // u1.Name = "赵六"; // 报错,init-only属性不可修改 ``` | 1. 不可变数据对象(如DTO、领域模型、配置对象);2. 需要值相等性判断的数据载体(避免重写Equals和GetHashCode);3. 简化数据对象的定义(减少模板代码);4. 函数式编程中的不可变数据场景 | 1. 核心特性:不可变性(默认字段为init-only,仅初始化时可赋值)、值相等性(默认比较字段值,而非引用)、with表达式(创建修改后的新实例);2. 记录类型默认重写Equals()、GetHashCode()、ToString()方法;3. 支持继承(record可继承record,不可继承class);4. 可定义为record struct(值类型记录),兼具值类型特性和记录功能;5. 与class的区别:class是引用相等,record是值相等;class可变,record默认不可变 |
| ref | 方法参数引用修饰符,按引用传递参数(需先初始化),允许方法修改原始变量 | csharp public void Increment(ref int value) { value++; } int num = 10; Increment(ref num); // num变为11 | 方法需要修改传入变量的值、大型值类型参数传递(避免拷贝) | 1. ref参数必须先初始化;2. 与out的区别:ref侧重“输入+输出”,out侧重“输出”;3. C# 7.0+支持ref返回值 |
| Reflection(反射) | 反射(System.Reflection命名空间),是.NET的核心功能,允许程序在运行时获取程序集、类型的元数据,并动态创建对象、调用方法、访问属性/字段 | ```csharp // 1. 获取类型信息 Type stringType = typeof(string); Console.WriteLine($"类型名:{stringType.Name}"); Console.WriteLine($"命名空间:{stringType.Namespace}"); // 2. 获取类型的方法 MethodInfo lengthMethod = stringType.GetMethod("Length", BindingFlags.Public | BindingFlags.Instance); MethodInfo concatMethod = stringType.GetMethod("Concat", BindingFlags.Public | BindingFlags.Static, new[] { typeof(string), typeof(string) }); // 3. 动态调用方法 string str = "hello"; int length = (int)lengthMethod.Invoke(str, null); // 调用实例方法 string concatResult = (string)concatMethod.Invoke(null, new object[] { "hello", "world" }); // 调用静态方法 // 4. 动态创建对象 Type personType = typeof(Person); Person person = (Person)Activator.CreateInstance(personType); // 调用无参构造函数 Person person2 = (Person)Activator.CreateInstance(personType, "张三", 28); // 调用带参构造函数 // 5. 访问属性 PropertyInfo nameProp = personType.GetProperty("Name"); nameProp.SetValue(person, "李四"); // 设置属性值 string name = (string)nameProp.GetValue(person); // 获取属性值 ``` | 1. 动态加载程序集和类型(如插件系统);2. 反射获取特性元数据(如前例的Attribute使用);3. 动态创建对象和调用方法(如依赖注入容器、序列化/反序列化);4. 通用框架开发(如ORM、MVC框架);5. 测试工具开发(反射调用私有方法) | 1. 核心类:Type(类型信息)、Assembly(程序集)、MethodInfo(方法信息)、PropertyInfo(属性信息)、FieldInfo(字段信息);2. 反射性能较低,尽量避免在高频执行代码中使用;3. 可访问私有成员(设置BindingFlags.NonPublic),但会破坏封装性,谨慎使用;4. 动态创建对象推荐使用Activator.CreateInstance(),动态调用方法使用MethodInfo.Invoke() |
| Regex | 正则表达式类(System.Text.RegularExpressions.Regex),用于处理字符串的正则匹配、替换、提取等操作,支持正则表达式语法 | ```csharp // 1. 验证字符串格式(邮箱验证) string email = "test@example.com"; string emailPattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"; bool isEmailValid = Regex.IsMatch(email, emailPattern); Console.WriteLine($"邮箱是否有效:{isEmailValid}"); // 2. 提取字符串中的数字 string str = "abc123def456ghi789"; string numberPattern = @"\d+"; MatchCollection matches = Regex.Matches(str, numberPattern); foreach (Match match in matches) { Console.WriteLine("提取的数字:" + match.Value); // 123、456、789 } // 3. 替换字符串 string dirtyStr = "Hello World"; string cleanStr = Regex.Replace(dirtyStr, @"<script.*?", "", RegexOptions.IgnoreCase); Console.WriteLine("过滤后的字符串:" + cleanStr); // 4. 分割字符串 string strToSplit = "a,b;c,d;e"; string[] parts = Regex.Split(strToSplit, @"[,;]"); // 按逗号或分号分割 foreach (var part in parts) { Console.WriteLine(part); // a、b、c、d、e } ``` | 1. 字符串格式验证(邮箱、手机号、身份证号、URL等);2. 字符串提取(如提取数字、日期、特定标签内容);3. 字符串替换/过滤(如过滤HTML标签、敏感词替换);4. 复杂字符串分割(多分隔符分割) | 1. 核心方法:IsMatch()(验证匹配)、Matches()(获取所有匹配项)、Replace()(替换匹配项)、Split()(分割字符串);2. 正则表达式语法:元字符(如\d数字、\w字母数字、.任意字符)、量词(如+一次或多次、*零次或多次、?零次或一次)、锚点(如^开头、$结尾);3. 可通过RegexOptions枚举设置匹配选项(如IgnoreCase忽略大小写、Multiline多行匹配);4. 复杂正则表达式建议预编译(Regex.CompileToAssembly),提高重复使用性能 |
| return | 返回语句关键字,用于退出方法并返回指定值(无返回值方法可省略返回值) | csharp public int Add(int a, int b) { return a + b; } public void PrintMsg() { Console.WriteLine("Hello"); return; // 可选,提前退出 } | 方法返回计算结果、提前终止方法执行(如参数校验失败后退出) | 1. 有返回值方法必须包含return语句(除非抛出异常);2. return后代码不执行;3. 异步方法中return对应Task<T>结果 |
| sbyte | 8位有符号值类型(System.SByte),范围-128~127,存储小范围有符号整数 | csharp sbyte temperature = -10; // 存储负数温度 sbyte offset = 30; int total = offset + 100; | 存储小范围有符号整数(温度、偏移量、误差值),需节省内存的场景 | 1. 默认值为0;2. 超出范围会溢出(需用checked检测);3. 不能隐式转换为int(需显式转换);4. 跨平台兼容性需注意(部分平台可能限制) |
| sealed | 密封修饰符,可修饰类、方法、属性,阻止继承或重写 | csharp // 密封类 sealed class Person { public virtual void Say() {} } // 密封方法 class Student : Person { public sealed override void Say() {} } | 1. 防止类被继承(如工具类、安全类);2. 防止方法被进一步重写(控制多态范围) | 1. 密封类不能作为基类;2. 密封方法必须是重写(override)的方法;3. 结构体默认密封,不能继承 |
| short | 16位有符号值类型(System.Int16),范围-32768~32767,存储短整数 | csharp short studentId = 1001; short score = -5; // 允许负数 | 存储小范围有符号整数(学号、分数、短计数),比int节省内存 | 1. 默认值为0;2. 超出范围会溢出;3. 与ushort(无符号)互斥;4. 常用于数据量较大的场景(如数组存储大量短整数) |
| sizeof | 运算符,用于获取值类型的字节大小(不能用于引用类型) | csharp int intSize = sizeof(int); // 4 byte byteSize = sizeof(byte); // 1 long longSize = sizeof(long); // 8 | 1. 内存优化(如计算数组占用内存);2. 底层编程(硬件交互、二进制序列化);3. 类型大小验证 | 1. 仅支持值类型(struct、基本类型),引用类型会编译报错;2. 结果为编译时常量;3. 不考虑装箱后的大小;4. 可用于unsafe代码块外(基本类型) |
| SortedSet<> | 泛型有序集合(System.Collections.Generic.SortedSet<T>),实现ICollection<T>和ISet<T>,存储不重复元素并按默认或自定义规则排序 | ```csharp // 初始化有序集合(默认升序) SortedSet<int> numbers = new SortedSet<int> { 5, 2, 8, 2, 1 }; foreach (var num in numbers) { Console.WriteLine(num); // 依次输出1、2、5、8(自动排序+去重) } // 自定义排序(降序) SortedSet<int> descendingNumbers = new SortedSet<int>(Comparer<int>.Create((a, b) => b.CompareTo(a))); descendingNumbers.AddRange(new[] { 3, 1, 4 }); foreach (var num in descendingNumbers) { Console.WriteLine(num); // 4、3、1 } // 范围操作 var range = numbers.GetViewBetween(2, 6); // 获取2-6之间的元素:{2,5} ``` | 1. 有序且唯一的元素存储(如排序后的ID列表);2. 范围查询场景(获取指定区间内的元素);3. 需要排序的集合运算;4. 无需手动排序的有序数据处理 | 1. 元素需实现IComparable<T>接口(默认排序),或初始化时指定自定义Comparer;2. 插入、删除、查找的时间复杂度为O(log n);3. 继承自ISet<T>,支持集合运算;4. 不支持索引访问,遍历始终按排序规则进行 |
| SortedSet<T> | 泛型有序集合(System.Collections.Generic.SortedSet<T>),基于红黑树实现,用于存储不重复且自动排序的元素,支持O(log n)时间复杂度的添加、删除、查找操作,元素按指定规则排序 | ```csharp // 1. 初始化SortedSet<T>(默认升序排序) SortedSet<int> numbers = new SortedSet<int>(); // 2. 添加元素(自动排序、去重) numbers.Add(3); numbers.Add(1); numbers.Add(2); numbers.Add(3); // 重复元素,添加失败 Console.WriteLine($"SortedSet元素(升序):{string.Join(",", numbers)}"); // 1,2,3 // 3. 自定义排序(降序) SortedSet<int> descendingNumbers = new SortedSet<int>(Comparer<int>.Create((a, b) => b.CompareTo(a))); descendingNumbers.Add(3); descendingNumbers.Add(1); descendingNumbers.Add(2); Console.WriteLine($"SortedSet元素(降序):{string.Join(",", descendingNumbers)}"); // 3,2,1 // 4. 自定义类型排序 public class Person { public string Name { get; set; } public int Age { get; set; } public override string ToString() { return $"{Name}({Age}岁)"; } } // 按年龄升序排序 SortedSet<Person> personSet = new SortedSet<Person>(Comparer<Person>.Create((p1, p2) => p1.Age.CompareTo(p2.Age))); personSet.Add(new Person { Name = "张三", Age = 28 }); personSet.Add(new Person { Name = "李四", Age = 22 }); personSet.Add(new Person { Name = "王五", Age = 30 }); Console.WriteLine("按年龄升序的Person集合:"); foreach (var p in personSet) { Console.WriteLine(p); // 李四(22岁)、张三(28岁)、王五(30岁) } // 5. 范围操作 SortedSet<int> rangeSet = new SortedSet<int> { 1, 2, 3, 4, 5, 6, 7, 8 }; // 获取小于5的所有元素 var lessThan5 = rangeSet.GetViewBetween(int.MinValue, 4); Console.WriteLine($"小于5的元素:{string.Join(",", lessThan5)}"); // 1,2,3,4 // 获取大于等于3且小于等于6的元素 var between3And6 = rangeSet.GetViewBetween(3, 6); Console.WriteLine($"3-6的元素:{string.Join(",", between3And6)}"); // 3,4,5,6 // 6. 集合运算(有序) SortedSet<int> set1 = new SortedSet<int> { 1, 2, 3, 4 }; SortedSet<int> set2 = new SortedSet<int> { 3, 4, 5, 6 }; // 交集(有序) set1.IntersectWith(set2); Console.WriteLine($"交集(有序):{string.Join(",", set1)}"); // 3,4 // 重置set1 set1 = new SortedSet<int> { 1, 2, 3, 4 }; // 并集(有序) set1.UnionWith(set2); Console.WriteLine($"并集(有序):{string.Join(",", set1)}"); // 1,2,3,4,5,6 ``` | 1. 有序去重场景(如存储有序的ID列表、排序后的名称列表);2. 范围查询场景(如获取指定区间内的元素);3. 有序集合运算场景(需要有序结果的交集、并集计算);4. 自动排序的缓存场景(如按时间排序的日志记录) | 1. 底层实现:基于红黑树(平衡二叉搜索树),确保元素有序且操作效率为O(log n);2. 排序规则:默认使用EqualityComparer<T>.Default(元素需实现IComparable<T>),也可通过构造函数指定自定义Comparer<T>;3. 核心特性:自动排序、不允许重复元素,支持范围查询;4. 范围操作:GetViewBetween(lowerBound, upperBound)方法获取指定区间的元素视图(视图是只读的,修改原集合会影响视图);5. 与HashSet<T>的区别:HashSet<T>无序,操作效率O(1);SortedSet<T>有序,操作效率O(log n);6. 与List<T>的区别:List<T>允许重复元素,需手动排序;SortedSet<T>自动去重排序;7. 限制:不支持通过索引访问元素,若需要索引访问,可先转换为List<T>(ToEnumerable().ToList()) |
| Span<T>/Memory<T> | 内存操作类型(System.Span<T>/System.Memory<T>,C# 7.2+),Span<T>是栈分配或非托管内存的连续内存块引用(值类型,不可装箱),Memory<T>是托管堆内存的连续内存块引用(引用类型,可装箱),均用于高效内存操作 | ```csharp // 1. Span<T>使用(栈内存、数组、非托管内存) // 数组转换为Span<T> int[] arr = new int[] { 1, 2, 3, 4, 5 }; Span<int> arrSpan = arr.AsSpan(); // 栈内存分配(stackalloc) Span<int> stackSpan = stackalloc int[5]; for (int i = 0; i < stackSpan.Length; i++) { stackSpan[i] = i * 2; } // 切片操作(无内存复制) Span<int> slice = arrSpan.Slice(1, 3); // 从索引1开始,长度3:[2,3,4] slice[0] = 20; // 修改切片会影响原数组 Console.WriteLine(arr[1]); // 20 // 内存复制(高效) Span<int> destSpan = new int[3]; slice.CopyTo(destSpan); Console.WriteLine(string.Join(",", destSpan)); // 20,3,4 // 2. Memory<T>使用(托管堆内存) Memory<int> memory = arr.AsMemory(); Memory<int> memorySlice = memory.Slice(1, 3); // 转换为Span<T>(临时访问) Span<int> memorySpan = memorySlice.Span; memorySpan[1] = 30; Console.WriteLine(arr[2]); // 30 // 异步场景使用Memory<T> async Task ProcessMemoryAsync(Memory<byte> data) { // 异步操作中使用Memory<T> await Task.Run(() => { Span<byte> span = data.Span; // 处理内存数据 for (int i = 0; i < span.Length; i++) { span[i] = (byte)(span[i] ^ 0xAA); // 简单加密示例 } }); } // 3. 字符串操作(ReadOnlySpan<char>) string str = "Hello World"; ReadOnlySpan<char> strSpan = str.AsSpan(); ReadOnlySpan<char> helloSpan = strSpan.Slice(0, 5); Console.WriteLine(helloSpan.ToString()); // Hello ``` | 1. 高效内存操作(如数据解析、加密解密、序列化);2. 避免内存复制(切片操作无复制);3. 栈内存分配场景(减少GC压力);4. 异步内存操作(Memory<T>支持异步场景);5. 字符串高效处理(ReadOnlySpan<char>避免字符串复制) | 1. 核心区别:Span<T>是值类型,仅能在栈上使用(不能作为类成员、不能跨异步操作);Memory<T>是引用类型,可在堆上使用(支持异步、可作为类成员);2. 只读版本:ReadOnlySpan<T>、ReadOnlyMemory<T>,用于不可修改的内存;3. 支持的内存来源:数组、栈内存(stackalloc)、非托管内存、字符串(ReadOnlySpan<char>);4. 性能优势:直接操作内存,避免中间内存复制,减少GC开销;5. 使用限制:Span<T>不能用于async方法、迭代器、闭包等场景(会超出栈生命周期);Memory<T>无此限制;6. 常用方法:Slice()(切片)、CopyTo()(复制)、TryCopyTo()(安全复制)、IndexOf()(查找) |
| Stack<> | 泛型栈(System.Collections.Generic.Stack<T>),实现ICollection<T>,遵循后进先出(LIFO)原则,支持压栈(添加顶部)和弹栈(移除顶部)操作 | ```csharp // 初始化栈 Stack<int> numberStack = new Stack<int>(); // 压栈(添加到顶部) numberStack.Push(1); numberStack.Push(2); numberStack.Push(3); // 查看顶部元素(不删除) int topNumber = numberStack.Peek(); // 3 // 弹栈(移除并返回顶部元素) while (numberStack.Count > 0) { int num = numberStack.Pop(); Console.WriteLine(num); // 依次输出3、2、1 } // 栈的应用:字符串反转 string str = "hello"; Stack<char> charStack = new Stack<char>(str); string reversed = new string(charStack.ToArray()); // "olleh" ``` | 1. 后进先出的数据处理(如撤销操作、表达式求值);2. 深度优先搜索(DFS)算法实现;3. 临时数据的栈式存储(用完即弃);4. 函数调用栈的模拟 | 1. 核心操作:Push(压栈)、Pop(弹栈)、Peek(查看顶部);2. 不支持索引访问,只能操作顶部元素;3. 内部通过数组实现,容量不足时自动扩容;4. 线程不安全,多线程环境需手动加锁或使用其他线程安全容器 |
| stackalloc | 栈内存分配关键字,在栈上分配数组内存(unsafe代码中使用),无需GC回收 | csharp unsafe { int* arr = stackalloc int[5]; for (int i = 0; i < 5; i++) { arr[i] = i * 2; } Console.WriteLine(arr[3]); // 6 } // 配合Span<T>(C# 7.2+) unsafe { Span<int> span = stackalloc int[5]; span[0] = 10; } | 1. 高性能、短生命周期的数组(如临时缓冲区);2. unsafe代码中的内存分配;3. 避免GC压力的场景 | 1. 仅在unsafe代码块中使用;2. 分配的内存位于栈上,函数返回后自动释放(无需手动管理);3. 栈内存大小有限制(避免分配过大数组导致栈溢出);4. 可配合Span<T>使用(类型安全,无需指针) |
| static | 静态修饰符,可修饰类、方法、属性、字段,属于类型本身而非实例 | csharp static class MathHelper { public static int Add(int a, int b) => a + b; } // 调用 int sum = MathHelper.Add(3,5); | 1. 工具类(无状态方法集合);2. 共享数据(如全局配置);3. 静态构造函数(初始化静态字段) | 1. 静态类不能实例化,不能有实例成员;2. 静态字段在程序启动时初始化,仅一次;3. 静态方法不能访问实例成员 |
| string | 引用类型(System.String),不可变的Unicode字符序列,用于存储文本 | csharp string name = "张三"; string fullName = "张" + "三"; bool isEqual = name.Equals("张三", StringComparison.Ordinal); | 存储文本数据(用户名、描述、配置信息等),所有文本处理场景 | 1. 不可变:修改会创建新实例;2. 用string.Empty表示空字符串(优于"");3. 支持插值表达式($"姓名:{name}");4. 可隐式转换为char[] |
| StringBuilder | 字符串构建器(System.Text.StringBuilder),引用类型,用于高效拼接大量字符串,避免string不可变导致的频繁内存分配 | ```csharp // 初始化StringBuilder StringBuilder sb = new StringBuilder(); // 追加字符串 sb.Append("Hello"); sb.Append(" "); sb.Append("World"); sb.AppendLine(); // 追加换行符 sb.AppendFormat("当前时间:{0:yyyy-MM-dd HH:mm:ss}", DateTime.Now); // 插入字符串 sb.Insert(5, ","); // 在索引5处插入逗号,结果变为"Hello, World" // 替换字符串 sb.Replace("World", "C#"); // 删除字符串 sb.Remove(5, 2); // 从索引5开始删除2个字符 // 转换为string string result = sb.ToString(); Console.WriteLine(result); ``` | 1. 大量字符串拼接场景(如日志生成、HTML构建、大文本拼接);2. 循环中动态构建字符串;3. 需要频繁修改字符串内容(插入、删除、替换);4. 性能敏感的字符串操作(避免string拼接的内存浪费) | 1. string不可变,拼接时会创建新实例,StringBuilder内部维护可变字符数组,减少内存分配;2. 核心操作:Append()、AppendLine()、AppendFormat()、Insert()、Replace()、Remove();3. 可指定初始容量(减少扩容次数,提高性能);4. 当拼接次数较少(如3次以内),string拼接性能接近StringBuilder,无需刻意使用;5. 最终需通过ToString()转换为string使用 |
| struct | 值类型结构体,用于封装小型相关数据(字段+方法),存储在栈上 | csharp struct Point { public int X { get; set; } public int Y { get; set; } public void Print() => Console.WriteLine($"({X},{Y})"); } Point p = new(){ X=1, Y=2 }; | 存储简单数据组合(坐标、颜色、尺寸),避免引用类型的内存开销 | 1. 不能继承类(可实现接口);2. 默认无无参构造函数(需显式定义);3. 赋值为值拷贝(非引用传递) |
| switch | 选择语句关键字,根据表达式值匹配case标签,执行对应代码块 | csharp int day = 3; switch (day) { case 1: Console.WriteLine("周一"); break; case 2: case 3: Console.WriteLine("周中"); break; default: Console.WriteLine("周末"); break; } | 多条件分支判断(如状态处理、类型判断)、替代多层if-else | 1. C# 7.0+支持模式匹配(如case int x when x>10);2. 无break会穿透(执行下一个case);3. default处理默认情况 |
| Task | 表示异步操作的引用类型(System.Threading.Tasks),用于异步编程 | csharp // 异步方法 async Task<string> GetDataAsync() { await Task.Delay(1000); return "数据"; } // 调用 var data = await GetDataAsync(); | 1. 异步IO操作(网络请求、文件读写);2. 耗时计算(避免阻塞UI线程);3. 并行任务 | 1. 需配合async/await关键字使用;2. Task<T>返回结果,Task无返回;3. 可通过Wait()阻塞等待(不推荐);4. 异常需用try-catch捕获 |
| Task/Task<T> | 任务并行库核心类(System.Threading.Tasks.Task/Task<TResult>),表示一个异步操作(可执行的工作单元),Task无返回值,Task<TResult>有返回值,是Async/Await的底层支撑 | ```csharp // 1. 创建并执行Task(无返回值) Task task1 = Task.Run(() => { Console.WriteLine("Task1开始执行"); Thread.Sleep(1000); // 模拟耗时操作 Console.WriteLine("Task1执行完成"); }); task1.Wait(); // 阻塞等待任务完成 // 2. 创建并执行Task<TResult>(有返回值) Task<int> task2 = Task.Run(() => { Console.WriteLine("Task2开始执行"); Thread.Sleep(1000); return 10 + 20; // 返回结果 }); int result = task2.Result; // 阻塞等待并获取结果 Console.WriteLine($"Task2结果:{result}"); // 3. 任务延续(Task.ContinueWith) Task task3 = Task.Run(() => 100); Task task4 = task3.ContinueWith(prevTask => { int prevResult = prevTask.Result; Console.WriteLine($"Task3结果:{prevResult},Task4继续执行"); }); task4.Wait(); // 4. 任务取消(CancellationToken) CancellationTokenSource cts = new CancellationTokenSource(); Task task5 = Task.Run(() => { for (int i = 0; i < 10; i++) { if (cts.Token.IsCancellationRequested) { Console.WriteLine("Task5被取消"); cts.Token.ThrowIfCancellationRequested(); // 抛出取消异常 } Thread.Sleep(500); Console.WriteLine($"Task5执行中:{i}"); } }, cts.Token); cts.CancelAfter(2000); // 2秒后取消任务 try { task5.Wait(); } catch (AggregateException ex) { Console.WriteLine($"捕获异常:{ex.InnerException.Message}"); } // 5. 异步方法返回的Task Task<int> asyncTask = CalculateSumAsync(5, 5); int asyncResult = await asyncTask; ``` | 1. 异步编程的底层封装(Async/Await基于Task实现);2. 并行任务执行(如多任务并发处理);3. 任务调度和管理(延续、取消、等待);4. 无Async/Await环境的异步操作(如旧版本框架);5. 批量任务处理(如Task.WhenAll、Task.WhenAny) | 1. 核心状态:Created(创建)、Running(运行中)、RanToCompletion(完成)、Faulted(失败)、Canceled(取消);2. 任务调度:默认使用ThreadPool(线程池)调度任务,也可自定义TaskScheduler;3. 等待任务的方式:await(非阻塞)、Wait()(阻塞)、Result(阻塞,获取返回值)、WhenAll(等待所有任务)、WhenAny(等待任一任务);4. 任务取消:通过CancellationTokenSource和CancellationToken实现,需在任务内部检查取消请求;5. 异常处理:任务执行过程中的异常会被包装为AggregateException,通过Task.Exception获取,或通过await直接捕获;6. Task.Run():快速将同步方法包装为异步任务(适合CPU密集型操作) |
| throw | 抛出异常关键字,用于主动触发异常(表示程序运行时错误) | ```csharp public void CheckAge(int age) { if (age < 0 | age > 120) { throw new ArgumentOutOfRangeException(nameof(age), "年龄必须在0-120之间"); } } ``` | |
| TimeSpan | 值类型(System.TimeSpan),用于表示时间间隔(两个DateTime之间的差值),可表示正数或负数,精度为100纳秒 | ```csharp // 构造时间间隔(2小时30分钟15秒) TimeSpan ts1 = new TimeSpan(2, 30, 15); // 通过DateTime差值获取 DateTime start = new DateTime(2024, 1, 1); DateTime end = new DateTime(2024, 1, 2); TimeSpan ts2 = end - start; // 1天 // 常用属性 double totalHours = ts1.TotalHours; // 2.504166... int minutes = ts1.Minutes; // 30 long ticks = ts1.Ticks; // 时间间隔的刻度数(1刻度=100纳秒) // 常用操作 TimeSpan ts3 = ts1.Add(TimeSpan.FromMinutes(10)); // 加10分钟 TimeSpan ts4 = TimeSpan.FromSeconds(60); // 1分钟 bool isLonger = ts2 > ts1; // true(1天>2小时30分) ``` | 1. 计算两个时间的差值(如任务执行耗时);2. 表示固定的时间间隔(如定时任务周期);3. 时间加减运算(如在某个时间基础上加1小时);4. 时间间隔的比较和格式化 | 1. 常用静态方法:FromDays()、FromHours()、FromMinutes()、FromSeconds()、FromMilliseconds();2. 最大值:TimeSpan.MaxValue(~10675199天),最小值:TimeSpan.MinValue(负最大值);3. 零间隔:TimeSpan.Zero;4. 可通过ToString()格式化输出(如"hh:mm:ss") |
| try-catch-finally | 异常处理结构:try包裹可能出错的代码,catch捕获异常,finally确保资源释放 | csharp try { var file = File.OpenRead("data.txt"); // 可能抛FileNotFoundException } catch (FileNotFoundException ex) { Console.WriteLine($"文件未找到:{ex.Message}"); } finally { file?.Dispose(); // 无论是否异常都执行 } | 所有可能发生异常的操作(文件读写、网络请求、数据库操作),保证程序稳定性 | 1. 可多个catch(按异常类型从具体到抽象排序);2. finally可选(但推荐用于释放资源);3. C# 6.0+支持异常筛选器(catch (Ex ex) when (条件)) |
| Tuple | 元组(System.Tuple),值类型(ValueTuple)或引用类型(Tuple<T1,...>),用于临时存储多个不同类型的数据,无需定义自定义类 | ```csharp // 1. 引用类型Tuple(.NET Framework兼容,不推荐) Tuple<string, int, bool> tuple1 = new Tuple<string, int, bool>("张三", 28, true); Console.WriteLine($"姓名:{tuple1.Item1},年龄:{tuple1.Item2},是否已婚:{tuple1.Item3}"); // 2. 值类型ValueTuple(C# 7.0+推荐,语法糖) (string Name, int Age, bool IsMarried) tuple2 = ("李四", 22, false); Console.WriteLine($"姓名:{tuple2.Name},年龄:{tuple2.Age},是否已婚:{tuple2.IsMarried}"); // 3. 简化语法(省略类型声明) var tuple3 = ("王五", 30, true); Console.WriteLine($"姓名:{tuple3.Item1},年龄:{tuple3.Item2}"); // 4. 方法返回多个值 (string, int) GetUserInfo() { return ("赵六", 35); } var (userName, userAge) = GetUserInfo(); // 解构赋值 Console.WriteLine($"姓名:{userName},年龄:{userAge}"); // 5. 元组比较(C# 7.3+) var t1 = (1, 2); var t2 = (1, 2); Console.WriteLine(t1 == t2); // True ``` | 1. 方法返回多个不同类型的值(无需定义输出参数或自定义类);2. 临时存储多个相关数据(如循环中的临时变量、查询结果的临时封装);3. 简单的数据传递(无需复杂对象的场景);4. 键值对之外的多字段临时组合 | 1. 推荐使用ValueTuple(值类型,性能更好,支持命名字段、解构、比较),替代旧的Tuple<T>(引用类型,无命名字段);2. ValueTuple语法糖:(T1 Name1, T2 Name2) 声明命名元组,var 自动推断类型;3. 解构赋值:通过(var a, var b) = tuple 快速获取元组字段;4. 元组字段默认名称为Item1、Item2...,命名元组可自定义名称;5. 不适合复杂数据传递(复杂场景推荐定义自定义类/结构体,提高可读性) |
| Type | 类型信息类(System.Type),封装了类型的元数据(如名称、命名空间、方法、属性等),是反射的核心类,用于在运行时获取和操作类型信息 | ```csharp // 三种获取Type对象的方式 Type intType1 = typeof(int); Type intType2 = 10.GetType(); Type intType3 = Type.GetType("System.Int32"); // 获取类型基本信息 Console.WriteLine(intType1.Name); // Int32 Console.WriteLine(intType1.Namespace); // System Console.WriteLine(intType1.IsValueType); // True(值类型) // 获取类型的公共属性 PropertyInfo[] props = intType1.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var prop in props) { Console.WriteLine(prop.Name); // 输出int的公共属性(如MinValue、MaxValue) } // 获取类型的公共方法 MethodInfo[] methods = intType1.GetMethods(BindingFlags.Public | BindingFlags.Instance); foreach (var method in methods) { if (method.Name == "ToString") { Console.WriteLine("找到ToString方法"); } } ``` | 1. 反射操作的基础(所有反射功能均依赖Type对象);2. 运行时类型判断(如判断对象是否为指定类型的子类);3. 动态获取类型成员(方法、属性、字段)并操作;4. 通用框架开发(如依赖注入、序列化) | 1. 无法直接实例化Type对象,需通过typeof()、GetType()或Type.GetType()获取;2. 核心功能:获取类型信息、成员信息,动态创建实例、调用成员;3. 支持判断类型特性(是否为值类型、引用类型、抽象类、接口等);4. 与Assembly类配合,可实现程序集级别的反射操作 |
| uint | 32位无符号值类型(System.UInt32),范围0~4294967295,存储无符号整数 | csharp uint fileSize = 4294967295; // 最大文件大小(4GB) uint counter = 0; counter++; | 1. 存储无符号整数(文件大小、计数器、ID);2. 需更大无符号范围场景 | 1. 默认值为0;2. 不能存储负数;3. 与int范围互补;4. 运算时需注意类型匹配(避免与int混用溢出) |
| ulong | 64位无符号值类型(System.UInt64),范围0~18446744073709551615 | csharp ulong largeCounter = 18446744073709551615UL; // 需加UL后缀 ulong diskSpace = 1000000000000UL; // 1TB | 1. 存储超大无符号整数(磁盘空间、硬件计数器、全局ID);2. 底层编程场景 | 1. 默认值为0;2. 常量需加UL/U后缀;3. 不能存储负数;4. 与long范围互补;5. 适合需要超过int/uint范围的无符号场景 |
| unchecked | 禁用溢出检查关键字,数值运算溢出时不抛出异常,直接截断高位 | csharp int max = int.MaxValue; int result = unchecked(max + 1); // 结果为int.MinValue,无异常 unchecked { int a = 2147483647; int b = a + 1; // 无异常,b=-2147483648 } | 1. 性能优先的场景(避免溢出检查开销);2. 已知不会溢出的运算;3. 依赖溢出截断的逻辑(如哈希计算) | 1. 与checked相对;2. 溢出时按模运算处理(如int溢出后循环到最小值);3. 可用于语句块或表达式;4. Release模式默认使用unchecked |
| unsafe | 不安全代码标记,允许使用指针、直接内存访问等非托管特性 | csharp unsafe { int num = 10; int* p = # Console.WriteLine(*p); // 输出10 } unsafe struct Data { public fixed int Values[10]; // 固定大小缓冲区 } | 1. 底层内存操作(如硬件驱动、高性能计算);2. 与非托管代码交互;3. 指针操作优化性能 | 1. 需在项目属性中启用“允许不安全代码”;2. 可能引发内存泄漏、访问违规等风险;3. fixed语句用于固定托管对象地址(避免GC移动);4. 指针类型需用*声明 |
| ushort | 16位无符号值类型(System.UInt16),范围0~65535,存储无符号短整数 | csharp ushort port = 8080; // 存储端口号 ushort count = 65535; // 最大值 | 1. 存储无符号短整数(端口号、索引、计数);2. 硬件编程、网络协议字段 | 1. 默认值为0;2. 与short(有符号短整数)范围互补;3. 显式转换为int可避免溢出;4. 不能用于负数场景 |
| using | 1. 引入命名空间;2. 声明资源释放(自动调用IDisposable.Dispose()) | csharp // 引入命名空间 using System.IO; // 资源释放 using (var stream = new FileStream("file.txt", FileMode.Open)) { // 操作流 } | 1. 简化代码(无需写完整命名空间);2. 释放非托管资源(文件流、数据库连接、网络连接) | 1. using声明(C# 8.0+):using var stream = new FileStream(...); 无需{};2. 必须实现IDisposable接口才能用using释放;3. 多个资源可并列声明(using (var a = ...; var b = ...)) |
| ValueTask/ValueTask<T> | 值类型任务(System.Threading.Tasks.ValueTask/ValueTask<TResult>,C# 7.0+),结构体类型,用于表示可能同步完成的异步操作,减少异步操作中的内存分配(替代Task/Task<T>) | ```csharp // 1. ValueTask<T>示例(可能同步完成的异步方法) public ValueTask<int> GetDataAsync(bool isSynchronous) { if (isSynchronous) { // 同步完成,直接返回结果(无内存分配) return new ValueTask<int>(42); } // 异步完成,返回Task<int>包装的ValueTask return new ValueTask<int>(Task.Run(() => { Thread.Sleep(1000); return 100; })); } // 2. 调用ValueTask<T>方法 async Task UseValueTask() { // 同步场景(无内存分配) ValueTask<int> syncTask = GetDataAsync(isSynchronous: true); int syncResult = syncTask.Result; // 同步获取结果(无阻塞) Console.WriteLine($"同步结果:{syncResult}"); // 异步场景 ValueTask<int> asyncTask = GetDataAsync(isSynchronous: false); int asyncResult = await asyncTask; // 异步等待 Console.WriteLine($"异步结果:{asyncResult}"); // 确保ValueTask只被等待一次(重要) try { await asyncTask; // 错误:ValueTask不能多次等待 } catch (InvalidOperationException ex) { Console.WriteLine($"错误:{ex.Message}"); } // 转换为Task(如需多次等待) Task<int> task = asyncTask.AsTask(); await task; await task; // 允许多次等待 } // 3. ValueTask(无返回值) public ValueTask DoWorkAsync(bool isSynchronous) { if (isSynchronous) { Console.WriteLine("同步完成工作"); return ValueTask.CompletedTask; // 静态完成实例 } return new ValueTask(Task.Run(() => { Thread.Sleep(1000); Console.WriteLine("异步完成工作"); })); } // 调用无返回值ValueTask await DoWorkAsync(isSynchronous: false); ``` | 1. 可能同步完成的异步操作(如缓存查询:缓存命中则同步返回,未命中则异步加载);2. 高频执行的异步方法(减少Task的内存分配开销);3. 轻量级异步操作(无需复杂任务调度);4. IAsyncDisposable.DisposeAsync()方法的返回值(标准用法) | 1. 核心优势:值类型,同步完成时无堆内存分配(Task是引用类型,始终有分配);2. 限制:ValueTask/ValueTask<T>只能被等待一次,多次等待会抛出异常(如需多次等待,需通过AsTask()转换为Task);3. 静态实例:ValueTask.CompletedTask(无返回值完成状态)、ValueTask.FromResult<T>(T result)(有返回值完成状态);4. 与Task的选择:同步完成概率高、高频调用的场景用ValueTask;需要多次等待、需要任务延续的场景用Task;5. 性能注意:避免将ValueTask存储或传递(仅在调用点等待),否则可能导致状态错误;6. 适用版本:.NET Core 2.1+、.NET Standard 2.1+、.NET 5+ |
| virtual | 虚方法修饰符,允许子类重写(override)基类方法,实现多态 | csharp class Animal { public virtual void MakeSound() => Console.WriteLine("动物叫"); } class Cat : Animal { public override void MakeSound() => Console.WriteLine("喵喵叫"); } | 父类定义通用方法,子类提供特定实现(如动物叫声、形状面积计算) | 1. 只能修饰方法、属性、索引器、事件;2. 静态方法、密封方法不能是虚方法;3. 子类未重写则调用基类实现 |
| void | 无返回值标识,用于方法返回类型,标识方法不返回任何结果 | csharp public void ShowMessage(string msg) { Console.WriteLine(msg); } void Main() { ShowMessage("测试"); } | 仅执行操作无需返回结果的方法(打印日志、修改状态、数据保存) | 1. 不能用于变量声明;2. 异步方法中对应Task(而非void);3. 不能用return返回值(可单独写return) |
| volatile | 易变字段修饰符,确保字段的读写操作不被编译器优化,直接访问内存 | csharp private volatile bool _isRunning = true; public void Stop() { _isRunning = false; } public void Run() { while (_isRunning) { // 执行任务 } } | 1. 多线程环境下共享字段(避免线程缓存导致的数据不一致);2. 硬件寄存器访问;3. 信号量、状态标记字段 | 1. 仅修饰字段(不能修饰方法、属性);2. 保证可见性,不保证原子性(复杂操作需配合lock);3. 支持的类型:sbyte、byte、short、ushort、int、uint、char、float、bool等;4. 避免编译器优化导致的字段读取缓存 |
| WeakReference(弱引用) | 弱引用(System.WeakReference/WeakReference<T>),用于引用对象但不阻止垃圾回收器(GC)回收该对象,当对象被GC回收后,弱引用的Target属性会变为null,适用于缓存等场景 | ```csharp // 1. 非泛型WeakReference // 创建强引用 object strongObj = new object(); Console.WriteLine($"强引用对象:{strongObj}"); // 创建弱引用(跟踪强引用对象) WeakReference weakRef = new WeakReference(strongObj); Console.WriteLine($"弱引用是否跟踪对象:{weakRef.IsAlive}"); // True // 释放强引用 strongObj = null; // 触发垃圾回收 GC.Collect(); GC.WaitForPendingFinalizers(); // 检查弱引用对象是否被回收 Console.WriteLine($"弱引用是否跟踪对象:{weakRef.IsAlive}"); // False object recoveredObj = weakRef.Target; Console.WriteLine($"回收后获取对象:{recoveredObj}"); // Null // 2. 泛型WeakReference<T>(C# 4.5+,推荐,避免装箱拆箱) string strongStr = "Hello WeakReference"; WeakReference<string> weakStrRef = new WeakReference<string>(strongStr); Console.WriteLine($"泛型弱引用是否跟踪对象:{weakStrRef.TryGetTarget(out string tempStr)}"); // True Console.WriteLine($"获取的对象:{tempStr}"); // Hello WeakReference // 释放强引用并触发GC strongStr = null; GC.Collect(); GC.WaitForPendingFinalizers(); Console.WriteLine($"泛型弱引用是否跟踪对象:{weakStrRef.TryGetTarget(out tempStr)}"); // False Console.WriteLine($"回收后获取对象:{tempStr}"); // 空字符串 // 3. 弱引用缓存示例 public class WeakCache<TKey, TValue> where TValue : class { private readonly Dictionary<TKey, WeakReference<TValue>> _cache = new Dictionary<TKey, WeakReference<TValue>>(); // 添加缓存 public void Add(TKey key, TValue value) { _cache[key] = new WeakReference<TValue>(value); } // 获取缓存 public bool TryGet(TKey key, out TValue value) { if (_cache.TryGetValue(key, out WeakReference<TValue> weakRef)) { if (weakRef.TryGetTarget(out value)) { return true; } _cache.Remove(key); // 对象已回收,移除无效弱引用 } value = null; return false; } } // 使用弱引用缓存 WeakCache<int, string> cache = new WeakCache<int, string>(); cache.Add(1, "缓存数据1"); if (cache.TryGet(1, out string data)) { Console.WriteLine($"获取缓存:{data}"); // 缓存数据1 } // 释放强引用并触发GC data = null; GC.Collect(); if (cache.TryGet(1, out data)) { Console.WriteLine($"获取缓存:{data}"); } else { Console.WriteLine("缓存数据已被回收"); } ``` | 1. 缓存场景(缓存大对象,不阻止GC回收,避免内存泄漏);2. 跟踪对象生命周期(判断对象是否被GC回收);3. 事件订阅管理(避免因事件订阅导致的对象无法回收);4. 资源敏感型场景(需要动态释放内存的场景) | 1. 核心特性:弱引用不增加对象的引用计数,不阻止GC回收;2. 泛型vs非泛型:WeakReference<T>是泛型版本,避免装箱拆箱,推荐使用;WeakReference是非泛型版本,Target属性返回object;3. 关键方法:WeakReference<T>.TryGetTarget(out T target)(安全获取目标对象,避免空引用);4. 短弱引用vs长弱引用:默认是短弱引用(对象析构后无法获取),长弱引用(即使对象析构后仍可获取,需通过构造函数指定trackResurrection: true);5. 注意事项:不能依赖弱引用的对象一定存在,使用前必须检查IsAlive或通过TryGetTarget验证;6. 适用对象:仅适用于引用类型,值类型会被装箱为引用类型;7. 内存泄漏避免:弱引用缓存需定期清理无效的弱引用(对象已回收的弱引用) |
| while | 循环语句关键字,用于未知循环次数的迭代(先判断条件,再执行循环体) | csharp int count = 0; while (count < 3) { Console.WriteLine("循环"); count++; } | 条件满足时持续执行(如用户输入验证、等待资源就绪)、无限循环(while(true)) | 1. 条件为true时执行循环体;2. 避免死循环(需确保条件能变为false);3. 比for循环更灵活(无固定迭代器) |
| yield | 迭代器关键字,用于简化IEnumerable/IEnumerable<T>的实现,延迟返回数据 | csharp public IEnumerable<int> GetEvenNumbers(int max) { for (int i = 0; i <= max; i += 2) { yield return i; // 延迟返回,每次迭代生成一个值 } } foreach (var num in GetEvenNumbers(10)) { Console.WriteLine(num); } | 生成大量数据(避免一次性加载到内存)、延迟计算(如分页数据、筛选结果) | 1. 配合yield return(返回元素)和yield break(终止迭代);2. 方法返回类型必须是IEnumerable/IEnumerable<T>;3. 迭代过程中状态会被保存,下次迭代从暂停处继续 |
| yield return/yield break | 迭代器关键字,yield return用于返回枚举序列的下一个元素,yield break用于终止枚举序列,自动生成实现IEnumerable</T>/IEnumerator<T>的代码 | ```csharp // 生成1到n的偶数序列 public IEnumerable<int> GetEvenNumbers(int n) { for (int i = 1; i <= n; i++) { if (i % 2 == 0) { yield return i; // 返回偶数,暂停迭代 } } // 循环结束自动终止,等价于yield break } // 生成指定条件的序列,满足条件后终止 public IEnumerable<string> GetNamesUntilStop() { yield return "张三"; yield return "李四"; yield break; // 终止迭代,后续元素不返回 yield return "王五"; // 不会执行 } // 调用 foreach (int even in GetEvenNumbers(10)) { Console.WriteLine(even); // 输出2、4、6、8、10 } foreach (string name in GetNamesUntilStop()) { Console.WriteLine(name); // 输出张三、李四 } ``` | 1. 简化IEnumerable<T>/IEnumerator<T>的实现;2. 延迟生成序列(遍历时时才生成元素,节省内存);3. 生成大型序列(避免一次性加载到内存);4. 条件性终止序列遍历 | 1. 使用yield的方法返回类型必须是IEnumerable、IEnumerable<T>、IEnumerator、IEnumerator<T>;2. yield return会暂停方法执行,下次遍历继续从暂停处执行;3. yield break强制终止序列,后续代码不执行;4. 自动处理枚举器的Dispose()逻辑;5. 不支持在try-catch块中使用yield(可在try-finally中使用) |