C#知识总结

目录

  • 一、C#基础语法知识入门
    • 1. 输入输出操作
    • 2. 变量类型与常量
      • 2.1基础类型
      • 2.2常量
    • 3. 转义字符
    • 4. 类型转换
      • 4.1隐式转换规则
      • 4.2显式转换 API
    • 5. 运算符
      • 运算符分类与优先级
    • 6. 流程控制
      • 6.1条件分支
      • 6.2循环
      • 6.3控制关键字
    • 7. 异常处理
  • 二、C#基础语法知识基础
    • 1.枚举、数组、结构体 vs 类对比
      • 1.1枚举(Enum)
      • 1.2数组(一维/二维/交错)
    • 2. 值类型 vs 引用类型
    • 3. 字符串操作
      • 3.1核心方法
      • 3.2性能优化
    • 4. 函数
      • 4.1ref & out
      • 4.2变长参数(params)& 默认值
      • 4.3函数重载
      • 4.4递归函数
  • 三、C#基础语法知识核心
    • 1、结构体与类
    • 2.访问修饰符详解
    • 3.构造函数、析构函数和垃圾回收
    • 4.静态成员、静态类与静态构造函数
    • 5.C# 封装高级特性:属性、索引器、拓展方法与运算符重载
    • 6.C# 类的常用使用规则
    • 7. 万物之父和装箱拆箱
    • 8. 抽象类和抽象方法、接口
      • 8.1抽象类和抽象方法和接口使用规则
      • 8.2抽象类和接口的区别
        • 8.2.1定义层面
        • 8.2.2使用层面
        • 8.2.3抽象类 vs 接口
    • 9.string和StringBuilder
      • 9.1. `string` 常用方法
      • 9.2. `StringBuilder` 常用方法
      • 9.3. `string` 与 `StringBuilder` 对比及内存优化
  • 四、C#基础语法知识进阶
    • 1.数据集合
      • 1.1 ArrayList
      • 1.2 Stack
      • 1.3 Queue
      • 1.4 Hashtable
      • 1.5 List
      • 1.6 Dictionary
      • 1.7 LinkedList
    • 2.泛型和泛型约束
      • 2.1 泛型基础
      • 2.2 泛型约束(`where` )关键字
    • 3.委托和事件
      • 3.1 委托(Delegate)
      • 3.2 事件(Event)
      • 3.3 关键对比与最佳实践
    • 4.匿名函数 vs Lambda 表达式和闭包
      • 4.1匿名函数 vs Lambda 表达式
      • 4.2闭包(Closure)
    • 5.协变(Out)与逆变(In)
    • 6.多线程基础
    • 7.预处理器指令
    • 8.反射
      • 8.1反射概念和作用
      • 8.2反射核心方法详解(Type/Assembly/Activator)
        • 8.2.1 Type 类:类型元数据访问(核心)**
        • 8.2.2 Assembly 类:程序集加载与解析
        • 8.2.3 Activator 类:对象实例化
        • 8.2.4 核心操作详解(含注意事项)
    • 9.特性
    • 10.迭代器(Iterator)
      • 10.1 传统实现和语法糖
      • 10.2 关键对比与规则
    • 11 特殊语法

一、C#基础语法知识入门

1. 输入输出操作

API 说明
Console.WriteLine 输出文本并换行(支持占位符,如 WriteLine("{0}", value))。
Console.Write 输出文本不换行。
Console.ReadLine 读取一行输入,返回字符串(用户输入以回车结束)。
Console.ReadKey 读取单个按键,返回 ConsoleKeyInfo(可捕获键盘事件)。

2. 变量类型与常量

2.1基础类型

分类 类型 默认值
有符号整型 sbyte(8位)、short(16位)、int(32位)、long(64位) 0
无符号整型 byte(8位)、ushort(16位)、uint(32位)、ulong(64位) 0
浮点数 float(单精度)、double(双精度)、decimal(高精度) 0.0
布尔/字符 booltrue/false)、char(单字符,如 'A' false/\0
字符串 string(引用类型,不可变) null

2.2常量

  • 声明const 类型 名称 = 值;(如 const float PI = 3.14f;)。
  • 特性:编译时常量,不可修改,必须初始化。

3. 转义字符

符号 含义 场景
\' 单引号 字符串中包含单引号(如 'Hello')。
\" 双引号 字符串中包含双引号(如 "World")。
\n 换行符 换行(如 str = "Line1\nLine2")。
\\ 反斜杠 文件路径(如 C:\\Folder\\File.txt)。
\t 制表符(Tab) 对齐文本(如 Name\tAge)。
\b 退格符 回退一格(如 12\b313)。
\a 警报音 触发系统提示音(慎用)。

4. 类型转换

4.1隐式转换规则

double → float → 整数(无符号/有符号) → chardecimal → 整数 → char
stringbool 不参与隐式转换)

4.2显式转换 API

方法 说明
(类型) 值 括号强转(如 (int)3.14
int.Parse(字符串) 字符串转 int(失败抛异常)
Convert.ToInt32(值) 任意类型转 32 位整数
ToString() 对象转字符串(重写自定义)

5. 运算符

运算符分类与优先级

类型 运算符 说明 优先级(高→低)
算术运算符 + - * / % 加减乘除取余(例:7 % 3 = 1 乘除取余(* / %)> 加减(+ -
赋值运算符 = += -= *= /= %= 赋值或复合运算(例:a += 2 → a = a + 2 最低
比较运算符 > < >= <= == != 比较结果为 bool(例:3 > 2 → true 高于逻辑运算符(除 ! 外)
逻辑运算符 ! && || 逻辑非、与、或(短路特性:
&& 左假则右不执行,
|| 左真则右不执行)
! > && > ||
位运算符 & | ^ ~ << >> 位运算(例:5 << 1 = 105 & 3 = 1 高于逻辑运算符(仅 ! 例外)
三目运算符 空位 ? 空位 : 空位 ` bool类型 ? bool类型为真返回内容 : bool类型为假返回内容;

6. 流程控制

6.1条件分支

语句 语法 特点
if if (条件) { 代码 } 单分支,条件为 true 执行。
if...else if (条件) { ... } else { ... } 双分支,条件为 false 执行 else
switch switch (变量) { case 常量: 代码; break; } 多分支,casebreak(支持贯穿)。

6.2循环

语句 语法 执行顺序
while while (条件) { 循环体 } 先判断,后执行(可能不执行)。
do...while do { 循环体 } while (条件); 先执行,后判断(至少一次)。
for for (初始; 条件; 增量) { 循环体 } 固定次数,适合已知范围。

6.3控制关键字

关键字 作用 适用场景
break 跳出当前循环或 switch 提前终止流程。
continue 跳过本次循环,继续下次 忽略后续代码,直接进入下次循环。

7. 异常处理

说明 是否必须
try 包含可能抛出异常的代码。
catch 捕获异常(可指定 Exception e 获取错误信息)。 是(至少一个)
finally 无论是否异常,最终执行(释放资源)。

示例结构

try { /* 风险代码 */ }
catch (Exception e) { /* 处理异常 */ }
finally { /* 清理资源 */ }

二、C#基础语法知识基础

1.枚举、数组、结构体 vs 类对比

1.1枚举(Enum)

分类 规则/特性 示例/说明 高频场景
声明 enum E_Type { A, B=5, C } 首项默认0,后续递增;自定义值从指定项开始 状态标识(如E_PlayerState.Idle
变量赋值 E_Type var = E_Type.B; 直接赋值枚举项 逻辑判断(if (var == E_Type.A)
类型转换 枚举→int:(int)var
字符串→枚举:(E_Type)Enum.Parse(typeof(E_Type), "B")
int num = (int)E_Type.A; // 0 配置表映射、日志输出
注意 声明在namespace/class,禁止函数内声明;避免魔数依赖 反例:不用int state = 0,改用枚举 提高代码可读性

1.2数组(一维/二维/交错)

类型 声明语法 索引方式 长度 内存 适用场景
一维数组 int[] arr = {1, 2, 3}; arr[索引](0-based) arr.Length(固定) 连续 线性数据(分数、ID列表)
二维数组 int[,] arr2D = {{1,2}, {3,4}}; arr2D[行, 列] arr2D.GetLength(0)(行数)
GetLength(1)(列数)
连续(按行存储) 规则表格(棋盘、矩阵)
交错数组 int[][] jagged = { new int[2], new int[3] }; jagged[行][列] jagged.Length(行数)
jagged[行].Length(每行长度)
不连续(子数组独立) 不规则数据(动态行列表)

2. 值类型 vs 引用类型

维度 值类型 引用类型 特殊引用(string)
存储位置 栈(直接存值) 堆(存值)+ 栈(存地址) 堆(存值)+ 栈(存地址)
赋值行为 深拷贝(独立,它变我不变) 浅拷贝(共享地址,它变我也变) 伪深拷贝(新建地址,它变我不变)
默认值 null(如int=0 null null
典型示例 intboolenumstruct int[]classobject string
内存管理 系统自动分配/释放(栈) 手动new,依赖GC(堆) 频繁new,需StringBuilder优化

3. 字符串操作

3.1核心方法

方法 说明
str + str2 拼接字符串
string.Format 格式化字符串
str.Length 获取字符串长度
str.IndexOf("子串") 查找子串位置(未找到返回 -1)
str.Substring(start, len) 截取子串

3.2性能优化

  • StringBuilder:高频拼接时使用(需 using System.Text;)。
    • 方法:Append()(追加)、Replace()(替换)、ToString()(转字符串)。

4. 函数

4.1ref & out

特性 ref out
核心 传递变量“内存地址”,双向修改 强制“输出参数”,必须方法内赋值
初始化 必须先赋值(传入前有值) 无需初始化(方法内必须赋值)
场景 交换变量、复杂计算修改原值 返回多个结果(替代 return)
示例 Swap(ref a, ref b) TryParse(out int result)

4.2变长参数(params)& 默认值

特性 params 默认值
核心 接收任意数量同类型参数 调用时可省略参数
规则 只能 1 个,且是最后一个参数 必须在参数列表末尾
场景 不定数量参数 常用参数简化调用
示例 Sum(1,2,3) Attack(damage: 100)

4.3函数重载

核心规则 示例
参数数量不同 Attack(int d) / Attack(int d, bool crit)
参数类型不同 Attack(float d) / Attack(string msg)
不能仅靠返回值重载 ❌ 无效 int Attack() {} vs void Attack() {}
编译器匹配逻辑 优先精确匹配 → 隐式转换

4.4递归函数

核心要素 示例(阶乘) 反例(无终止)
终止条件 if(n==0) return 1; Loop(); 无限递归
状态逼近 n * Factorial(n-1) 每次调用趋近终止条件
栈溢出风险 慎用深层递归(>1000 层) 改用迭代优化性能

三、C#基础语法知识核心

1、结构体与类

特性 结构体(值类型) 类(引用类型)
存储位置 栈(轻量,直接存值) 堆(存值)+ 栈(存地址)
继承 不能继承类,可实现接口 支持单类继承 + 多接口
构造函数 必须初始化所有成员,无默认无参 可选无参,成员默认初始化(如int=0
赋值行为 深拷贝(独立,修改互不影响) 浅拷贝(共享地址,修改联动)
默认值 null(如int=0bool=false null(未初始化时)
适用场景 轻量数据(坐标Point、颜色Color 复杂对象(玩家Player、场景Scene

2.访问修饰符详解

访问修饰符 访问权限 说明 默认使用场景
public 公共的,自己(内部)和别人(外部)都能访问和使用 该修饰符修饰的成员可在任何地方被访问,常用于暴露类的功能给外部调用。 当你希望类或成员能被项目内所有代码自由访问时使用,比如一些工具类的公共方法。
private 私有的,自己(内部)才能访问和使用,不写默认为 private 用它修饰的成员只能在声明该成员的类内部被访问,用于隐藏类的实现细节,防止外部直接修改。 当你想把类的某些实现细节隐藏起来,只在类内部使用时,如类的私有字段和方法。
protected 保护的,自己(内部)和子类才能访问和使用 此修饰符修饰的成员能在声明该成员的类及其派生类中被访问,常用于实现继承体系中的代码复用与保护。 当你希望类的某些成员可以被子类访问,但又不想让外部直接访问时,比如基类中的受保护方法,子类可以继承和重写。
internal 内部的,同一个程序集(通常是同一个项目)内可以访问 internal 修饰的成员能在定义它的程序集(项目)内被访问,在不同程序集里无法访问,用于限制访问范围在项目内部。 当你希望类或成员只能在当前项目中被访问,而对其他项目隐藏时,比如项目内部的辅助类和工具方法。

3.构造函数、析构函数和垃圾回收

类别 详情
构造函数
概念:实例化对象时调用的初始化函数,未自定义则有默认无参构造。
规则:无返回值,函数名与类名相同,常用 public 修饰,支持重载,可用 this 指代当前对象。
注意:实现有参构造会覆盖默认无参构造。
特殊用法:用 this(参数列表) 重用构造函数代码,先执行 this 后构造函数,再返回当前构造函数。
析构函数
概念:引用类型堆内存回收时调用,C# 有 GC,极少使用,Unity 开发基本不用。
语法~类名() { /* 代码 */ }
垃圾回收机制(GC)
概念:遍历堆上对象,回收无引用的垃圾对象。
算法:采用分代算法,分 0、1、2 代内存,新对象在 0 代,回收时先标记可达对象,再释放未标记对象并搬迁可达对象,大对象(>85000 字节)为 2 代,不搬迁压缩。
注意:GC 仅处理堆内存,引用类型堆内存由 GC 管理,值类型栈内存由系统自动管理。
手动触发GC.Collect();,一般在 Loading 场景时用,不常调用。

4.静态成员、静态类与静态构造函数

类别 使用规则 核心说明
静态成员 static 修饰,属于类本身,所有实例共享,通过类名.成员直接访问(无需实例化)。 用于全局状态(如计数器)或工具方法(如 Math.PI),避免重复实例化。
静态类 static 修饰,仅含静态成员,不可实例化(无构造函数),强制所有成员为静态。 封装无状态的工具逻辑(如 FileHelper),提升代码规范性(如 LogHelper.Info())。
静态构造函数 无访问修饰符,无参数,与类名相同,首次使用类或其静态成员时自动执行(CLR 触发)。 初始化静态成员(如加载配置文件),仅执行一次,无需手动调用。

5.C# 封装高级特性:属性、索引器、拓展方法与运算符重载

类别 使用规则 核心说明
成员属性 通过 get/set 封装字段,控制读写逻辑(如校验值范围),支持自动属性(public int Age { get; set; })。 隐藏字段细节,实现数据验证(如set { if (value>0) _age=value; }),提升封装性。
索引器 this[索引] 定义,支持对象通过索引访问(如obj[0] = value),可重载参数类型(如字符串索引)。 模拟数组行为,增强对象易用性(如Dictionary[key]),索引器本质是特殊属性。
拓展方法 在静态类中定义,首个参数用 this 修饰目标类型(如public static void Ext(this string s)),扩展现有类型功能。 为非自定义类型添加方法(如"abc".IsValid()),避免继承或修改原始代码。
运算符重载 operator 关键字为自定义类型重定义运算符(如+==),需成对实现(如==!=)。 让自定义类型支持内置运算符(如Vector2 a + b),提升代码可读性(替代Add()方法)。

6.C# 类的常用使用规则

类别 子类别 使用规则 核心说明
内部类 内部类 在外部类内部定义,可访问外部类所有成员(包括私有成员)。 封装紧密关联的辅助类,增强代码内聚性(如事件处理器嵌套在主类中)。
分部类 分部类 partial 修饰类,允许将类定义拆分到多个文件(同一命名空间)。 适合大型类或自动生成代码(如UI设计器+手工逻辑),提升协作效率。
继承 里氏替换原则 子类对象可无缝替换父类对象,程序行为不变(子类行为兼容父类)。 确保继承体系的稳定性,避免子类破坏父类契约(如不缩小方法访问权限)。
继承中的构造函数 子类构造函数默认调用父类无参构造;若父类无无参构造,需显式用 base(参数) 调用。 保证父类成员正确初始化(如 class Child : Parent { public Child() : base(10) { } })。
多态 virtual 父类方法声明为虚方法,允许子类重写(非强制)。 定义可扩展的方法模板(如 public virtual void Draw() { })。
override 子类用 override 重写父类 virtual 方法,实现差异化逻辑。 子类定制父类行为(如 public override void Draw() { 绘制圆形 })。
base 子类中通过 base.成员 调用父类方法/属性,复用父类逻辑。 在重写方法中保留父类行为(如 base.Draw(); 补充子类逻辑)。
密封类 密封类 sealed 修饰类,禁止被继承(密封类不能有子类)。 固定类的实现,防止被修改(如工具类 sealed class MathHelper { })。
密封方法 密封方法 子类用 sealed override 修饰重写方法,禁止孙类进一步重写。 固定关键逻辑(如 public sealed override void Finalize() { })。

7. 万物之父和装箱拆箱

类别 使用规则 常用 API 作用说明 核心说明
万物之父(object object 是所有类型的基类,任何类型可隐式转 object 类型。 ToString() 将对象转换为字符串,默认返回类型名,可重写增强可读性 作为基类,提供通用方法,方便对不同类型对象进行操作。
Equals() 比较两个对象是否相等,默认比引用,可重写实现值比较
GetHashCode() 返回对象哈希码,重写 Equals() 时通常也要重写此方法
GetType() 动态获取对象运行时的类型信息
MemberwiseClone() 实现对象浅拷贝,值类型独立复制,引用类型共享引用
ReferenceEquals() 判断两个对象引用是否指向同一位置,值类型通常返回 false
装箱 值类型转引用类型(object 类型)。 直接赋值 使值类型可当作引用类型处理 使值类型可用于需引用类型的场景。
拆箱 引用类型(object 类型)转原值类型,需显式转换。 强制类型转换 将装箱的值类型对象还原为原始值类型 将之前装箱的值类型对象还原。

8. 抽象类和抽象方法、接口

8.1抽象类和抽象方法和接口使用规则

类别 子类别 使用规则 常用 API 核心说明
抽象类和抽象方法 抽象类 abstract 修饰,不能实例化,只能作为基类被继承。可包含抽象方法和非抽象方法、字段等。 abstract 为子类提供通用的属性和方法框架,强制子类遵循特定的设计,适用于有一定共性实现的类体系。
抽象方法 abstract 修饰,无方法体,子类必须重写。 abstract 定义子类必须实现的行为,实现多态性。
接口 接口 interface 定义,只包含方法、属性、索引器和事件的声明,没有字段,成员默认是 public 且不能有访问修饰符,实现类必须实现所有成员。 interface 定义一组行为规范,允许类实现多个接口,增强代码的灵活性和可扩展性,适用于不同类之间需要实现相同行为的场景。

8.2抽象类和接口的区别

8.2.1定义层面
  • 成员类型:抽象类可以包含抽象方法、非抽象方法、字段、属性等;接口只能包含方法、属性、索引器和事件的声明。
  • 访问修饰符:抽象类中的成员可以使用各种访问修饰符;接口中的成员默认是 public 且不能有访问修饰符。
8.2.2使用层面
  • 继承关系:一个类只能继承一个抽象类;一个类可以实现多个接口。
  • 实例化:抽象类不能实例化;接口也不能实例化。
  • 设计目的:抽象类是对一类事物的抽象,是一种模板式设计;接口是对行为的抽象,是一种行为的规范。
8.2.3抽象类 vs 接口
特性 抽象类(abstract class 接口(interface
成员变量 支持 不支持
构造函数 支持(子类调用 base 不支持
继承 单继承 多继承
实现约束 抽象方法必须实现,虚方法可选 所有成员必须实现
场景 对象模板(如 Animal 行为规范(如 IFly

9.string和StringBuilder

9.1. string 常用方法

方法 作用 示例代码
[index] 通过索引获取指定位置字符,类似数组索引器。 string string2 = "林文韬"; Console.WriteLine(string2[0]); // 林
ToCharArray() 将字符串转为 char 数组。 char[] chars = string2.ToCharArray(); Console.WriteLine(chars[1]); // 文
Format() 字符串拼接,有多个重载。 string string3 = string.Format("{0}{1}{2}", 183, 1834, 8848); Console.WriteLine(string3); // 18318348848
IndexOf() 正向查找字符或字符串位置,返回首个匹配字符索引,未找到返回 -1。 string string4 = "我是林文韬"; int index = string4.IndexOf("林"); Console.WriteLine(index); // 2
LastIndexOf() 反向查找字符串位置,返回最后匹配的首个字符索引,未找到返回 -1。 string string5 = "我是林文韬林文韬"; index = string5.LastIndexOf("林文韬"); Console.WriteLine(index); // 5
Remove() 移除指定位置后的字符,有两个重载,原字符串不变,返回新字符串。 string string6 = "我是林文韬林文韬"; string6 = string6.Remove(4); Console.WriteLine(string6); // 我是林文
Replace() 替换指定字符串,原字符串不变,返回新字符串。 string string7 = "我是林文韬林文韬"; string7 = string7.Replace("林文韬", "老炮儿"); Console.WriteLine(string7); // 我是老炮儿老炮儿
ToUpper()ToLower() 大小写转换,原字符串不变,返回新字符串。 string string8 = "linwentaozhendeshuai"; string8 = string8.ToUpper(); Console.WriteLine(string8); // LINWENTAOZHENDESHUAI
Substring() 字符串截取,有两个重载,原字符串不变,返回新字符串,需注意越界问题。 string string9 = "林文韬林文韬"; string9 = string9.Substring(2); Console.WriteLine(string9); // 韬林文韬
Split() 字符串切割,返回 string 数组。 `string string10 = "1_1

9.2. StringBuilder 常用方法

方法 作用 示例代码
Append() 在尾部直接拼接字符串。 stringBuilder1.Append("4444"); Console.WriteLine(stringBuilder1); // 1231231234444
AppendFormat() 按指定格式在尾部拼接字符串。 stringBuilder1.AppendFormat("{0}{1}", 100, 999); Console.WriteLine(stringBuilder1); // 1231231234444100999
Insert() 在指定索引位置插入字符串。 stringBuilder1.Insert(1, "林文"); Console.WriteLine(stringBuilder1); // 1林文231231234444100999
Remove() 移除指定索引开始的指定长度字符。 stringBuilder1.Remove(0, 10); Console.WriteLine(stringBuilder1); // 234444100999
[index] 索引器,可 getset 字符。 Console.WriteLine(stringBuilder1[1]); // 3 stringBuilder1[0] = 'A'; Console.WriteLine(stringBuilder1); // A34444100999
Replace() 替换指定字符串,直接修改原对象。 stringBuilder1.Replace("1", "林"); Console.WriteLine(stringBuilder1); // A34444林00999
Clear() 清空字符串。 stringBuilder1.Clear(); Console.WriteLine(stringBuilder1); // 输出空
Equals() 判断是否和某字符串相等。 stringBuilder1.Append("林文真的帅"); if (stringBuilder1.Equals("林文真的帅")) { Console.WriteLine("相等"); // 相等 }

9.3. stringStringBuilder 对比及内存优化

对比项 string StringBuilder
内存使用 不可变,修改操作创建新对象,易产生垃圾。 可变,在现有对象基础上修改,节省内存。
灵活性 提供丰富操作方法,处理方便。 主要用于频繁拼接和修改,方法相对简单。
使用场景 需要使用独特方法处理特殊逻辑时使用。 需要频繁修改拼接字符串时使用。

四、C#基础语法知识进阶

1.数据集合

1.1 ArrayList

本质 申明 增删查改和遍历 装箱拆箱
object 类型数组( 不支持泛型 using System.Collections;
ArrayList arrayList = new ArrayList();
增:AddAddRangeInsert
删:RemoveRemoveAtClear
查:[]ContainsIndexOfLastIndexOf
改:[] =
遍历:CountCapacityforforeach
存储值类型时装箱,取出转换使用时拆箱

1.2 Stack

本质 申明 增取查改和遍历 装箱拆箱
object[] 数组,先进后出(支持泛型) using System.Collections;
Stack stack = new Stack();
增:Push
取:Pop
查:PeekContains
改:无(可 Clear
遍历:CountforeachToArraywhile 弹栈
存储值类型时装箱,取出转换使用时拆箱

1.3 Queue

本质 申明 增取查改和遍历 装箱拆箱
object[] 数组,先进先出(支持泛型) using System.Collections;
Queue queue = new Queue();
增:Enqueue
取:Dequeue
查:PeekContains
改:无(可 Clear
遍历:CountforeachToArraywhile 出队
存储值类型时装箱,取出转换使用时拆箱

1.4 Hashtable

本质 申明 增删查改和遍历 装箱拆箱
基于键的哈希代码组织的键/值对( 不支持泛型 using System.Collections;
Hashtable hashtable = new Hashtable();
增:Add
删:RemoveClear
查:[]ContainsContainsKeyContainsValue
改:[] =
遍历:Countforeach 键、foreach 值、foreach 键值对、迭代器遍历
存储值类型时装箱,取出转换使用时拆箱

1.5 List

本质 申明 增删查改和遍历 特点
可变类型的泛型数组(支持泛型) using System.Collections.Generic;
List list = new List();
增:AddAddRangeInsert
删:RemoveRemoveAtClear
查:[]ContainsIndexOfLastIndexOf
改:[] =
遍历:CountCapacityforforeach
基本无装箱拆箱(泛型非 object 时)

1.6 Dictionary

本质 申明 增删查改和遍历 特点
拥有泛型的 Hashtable,键/值对(支持泛型) using System.Collections.Generic;
Dictionary dictionary = new Dictionary();
增:Add
删:RemoveClear
查:[]ContainsKeyContainsValue
改:[] =
遍历:Countforeach 键、foreach 值、foreach 键值对
键值对类型可自定义泛型

1.7 LinkedList

本质 申明 增删查改和遍历
可变类型的泛型双向链表(支持泛型) using System.Collections.Generic;
LinkedList linkedList = new LinkedList();
增:AddLastAddFirstAddAfterAddBefore
删:RemoveFirstRemoveLastRemove
查:FirstLastFindContains
改:修改节点 Value 属性
遍历:foreach、节点 while 循环(从头到尾、从尾到头)

2.泛型和泛型约束

2.1 泛型基础

分类 语法 示例 作用
泛型类 class 类名 class Box { public T Value; }
Box box = new(); box.Value = 10;
类型参数化,支持不同类型的相同逻辑(如容器类)。
泛型接口 interface 接口名 interface IContainer { K Get(); }
class IntContainer : IContainer { ... }
定义类型无关的接口契约,实现多态。
泛型方法 public void 方法名(T 参数) void Print(T value) => Console.WriteLine(value);
Print("Hello"); // 类型推断
单个方法的类型参数化,避免代码冗余。
泛型占位符 大写字母(如TKV),可多个 Dictionary 代表未知类型,使用时指定具体类型(如Dictionary)。

2.2 泛型约束(where )关键字

约束类型 语法 约束内容 示例 注意事项
值类型 where T : struct T 必须是值类型(如intstruct)。 class ValueHolder where T : struct { ... }
ValueHolder vh;
不能与 new() 组合(值类型默认有无参构造)。
引用类型 where T : class T 必须是引用类型(如classinterface)。 class RefHolder where T : class { ... }
RefHolder rh;
可约束接口(如where T : IList)。
无参构造 where T : new() T 必须有公共无参构造函数。 class Creator where T : new() { T Create() => new T(); } 需写在 classstruct 之后(如where T : class, new())。
基类/派生类 where T : BaseClass T 必须是 BaseClass 或其子类。 class ShapeHolder where T : Shape { ... }
ShapeHolder sh;
不能约束密封类(如string)。
接口 where T : IInterface T 必须实现 IInterface 或其子接口。 class Runner where T : IRunner { ... }
Runner runner;
可组合多个接口(如where T : IRead, IWrite)。
泛型依赖 where T : U T 必须是另一个泛型类型 U 或其子类。 class Child where T : U { ... }
Child child;
用于泛型类的层级约束。
多约束组合 where T : class, new(), ILog 组合多个约束(顺序固定:class/structnew() → 接口/类)。 class Logger where T : class, new(), ILog { ... } struct 不能与 class 共存,new() 不能单独用于 struct

3.委托和事件

3.1 委托(Delegate)

分类 语法 示例 核心特性
自定义委托 delegate 返回值 委托名(参数列表); delegate int MyDelegate(int a);
MyDelegate del = ReturnInt;
定义函数类型,存储/传递方法,支持多播(+=/-=)。
系统委托 Action< T1, T2 >(无返回)
Func< T1, TRes >(有返回)
Action action = Console.WriteLine;
Func func = x => x > 0;
预定义泛型委托,Action无返回,Func最后一个类型为返回值,支持0~16参数。
多播委托 del += 方法名; del -= 方法名; del += Method1; del += Method2; del();(按添加顺序执行) 存储多个方法,执行时依次调用,移除首个匹配方法。
使用场景 回调函数、事件订阅、异步操作 Button.Click += OnClick; 解耦代码,实现松耦合的消息传递。

3.2 事件(Event)

特性 委托 事件 关键区别
申明 public MyDelegate del; public event MyDelegate evt; 事件需用event关键字,限制外部访问。
外部操作 可赋值(del = null;)、调用(del(); 仅可加减(evt += 方法;),不可赋值或调用 安全性:防止外部随意修改/触发,仅允许类内封装调用(如if (evt != null) evt();)。
存储位置 可作为局部变量 只能是类/接口的成员 事件是委托的“安全包裹”,强制封装。
典型场景 临时函数存储 按钮点击、状态变更等事件通知 事件驱动编程,如UI交互、游戏对象状态同步。

3.3 关键对比与最佳实践

场景 推荐方案 原因
临时回调 Lambda 表达式 简洁,无需定义单独方法。
事件订阅 事件(Event) + Lambda 安全封装,避免外部误操作。
需要移除的订阅 具名方法 + 事件 可通过-=精确移除。
状态保持 闭包 封装私有状态,避免污染作用域。
多参数复杂逻辑 自定义委托 + 具名方法 提高可读性,便于调试。

4.匿名函数 vs Lambda 表达式和闭包

4.1匿名函数 vs Lambda 表达式

类型 语法 示例 特性
匿名函数 delegate (参数) { 逻辑; } Action a = delegate() { Console.WriteLine("匿名"); }; 无函数名,依附委托存在,无法单独移除(无引用)。
Lambda (参数) => { 逻辑; }(参数) => 表达式 Func lambda = x => x.ToString(); 匿名函数的简写,省略delegate,参数类型可推断(如(x) => x*2)。
参数省略 无参数:() => {...}
单参数:x => {...}
Action noParam = () => Console.WriteLine();
Func add = x => x + 1;
简化代码,提升可读性,广泛用于LINQ、事件订阅。
缺点 无法指定移除(无名称) evt += () => {...};(只能整体清空) 适合临时逻辑,不适合需要精确控制的场景(如需要移除特定订阅)。

4.2闭包(Closure)

概念 示例 核心规则
捕获外部变量 csharp
int count = 0;
Action increment = () => count++;
increment(); // count=1
内层函数(Lambda/匿名函数)引用外层作用域的变量,延长变量生命周期。
变量捕获 csharp
for (int i=0; i<10; i++) {
evt += () => Console.WriteLine(i); // 全部输出10
}
捕获的是变量引用而非值,最终使用循环结束时的最终值(需用int index = i;保存当前值)。
使用场景 计数器、延迟执行、状态保持 封装状态,避免全局变量,如游戏中的技能冷却计时器。

5.协变(Out)与逆变(In)

分类 协变(Out) 逆变(In)
修饰符 out(仅接口/委托泛型) in(仅接口/委托泛型)
作用 子类 → 父类(返回值类型) 父类 → 子类(参数类型)
语法 delegate T Factory(); delegate void Action(T value);
示例 IEnumerableIEnumerable ActionAction
规则 泛型仅作返回值,遵循里氏替换 泛型仅作参数,参数兼容里氏替换
记忆 Out 产(返回),顺(子→父) In 消(参数),逆(父→子)

6.多线程基础

概念 关键 API 与规则 场景
开启线程 new Thread(Method).Start();(需 using System.Threading 异步逻辑(如网络请求、寻路)
后台线程 thread.IsBackground = true;(主线程结束后自动终止) 非关键任务(日志、心跳检测)
线程同步 lock (obj) { ... }(互斥锁,防竞态条件) 共享资源(如控制台、计数器)
优雅终止 标志位控制:static bool isRunning;(推荐)
thread.Abort()(慎用,.NET Core 可能报错)
避免死循环阻塞
线程休眠 Thread.Sleep(1000);(当前线程休眠 1 秒) 控制执行节奏

7.预处理器指令

指令 作用 示例
#define 定义编译符号(无值变量) #define UNITY_2024
#if UNITY_2024 ... #endif
#if/#elif 条件编译(平台/版本适配) csharp
#if IOS
苹果逻辑
#elif ANDROID
安卓逻辑
#endif
#warning 编译警告(不中断) #warning "旧版本兼容代码"
#error 编译错误(中断编译) #error "不支持该平台"
#region 折叠代码块(提升可读性) #region 初始化代码
...
#endregion

8.反射

8.1反射概念和作用

类别 详细内容
基础概念 编译器:将源语言程序(如 C#、C、C++、Java 程序)翻译成目标语言程序(二进制伪机器代码程序)
程序集:编译器编译的中间产物,Windows 下为 .dll 或 .exe 文件,是代码集合
元数据:描述程序的数据,如类、函数、变量信息,存于程序集中
反射:程序运行时查看其他或自身程序集元数据,获取类、函数等信息并操作
反射作用 提高程序扩展性和灵活性,运行时获取元数据、实例化对象、操作对象和创建新对象执行任务
关键类及功能 Type 类:反射基础,访问元数据,获取类型声明信息,如构造函数、方法等。获取方式有对象调用 GetType()typeof 关键字、Type.GetType() 方法
Assembly 类:加载其他程序集,使用前需引用 System.Reflection 命名空间。加载方法有 LoadLoadFromLoadFile
Activator 类:将 Type 对象快速实例化为对象,CreateInstance 方法可根据构造函数参数实例化对象

8.2反射核心方法详解(Type/Assembly/Activator)

8.2.1 Type 类:类型元数据访问(核心)**
方法 作用 参数 示例
GetType() 对象获取自身 Type(运行时类型) int a = 0; Type t = a.GetType();
typeof(类型) 编译时获取类型 Type 类型名(如 typeof(int) Type t = typeof(string);
Type.GetType(类名) 字符串形式获取 Type(需完整命名空间) 类全名(如 "System.Int32" Type t = Type.GetType("CSharpTest.TestClass");
Assembly属性 获取类型所在程序集 Console.WriteLine(t.Assembly.FullName);
GetMembers() 获取所有公共成员(方法、构造、字段等) MemberInfo[] members = t.GetMembers();
GetMembers(BindingFlags) 按标志获取成员(公共/私有/实例/静态) BindingFlags.Public/NonPublic/Instance/Static `t.GetMembers(BindingFlags.NonPublic
GetConstructors() 获取所有公共构造函数 ConstructorInfo[] ctors = t.GetConstructors();
GetConstructor(Type[]) 按参数类型获取指定构造函数 参数类型数组(如 new Type[] { typeof(int) } ConstructorInfo ctor = t.GetConstructor(new Type[0]); // 无参构造
GetFields() 获取所有公共字段 FieldInfo[] fields = t.GetFields();
GetField(字段名) 按名称获取公共字段 字段名(如 "j" FieldInfo field = t.GetField("j");
GetMethods() 获取所有公共方法 MethodInfo[] methods = t.GetMethods();
GetMethod(方法名, Type[]) 按名称+参数类型获取指定方法(区分重载) 方法名,参数类型数组 MethodInfo method = t.GetMethod("Speak", Type.EmptyTypes);
GetProperty(属性名) 获取公共属性 属性名(如 "Length" PropertyInfo prop = typeof(string).GetProperty("Length");
GetInterface(接口名) 获取实现的接口 接口名(如 "IEnumerable" Type iface = t.GetInterface("IComparable");
8.2.2 Assembly 类:程序集加载与解析
方法 作用 参数 示例
Load(程序集名) 加载当前目录的程序集(如 DLL/EXE) 程序集名称(如 "CSharpTest" Assembly asm = Assembly.Load("CSharpTest");
LoadFrom(路径) 加载指定路径的程序集(含路径+文件名) 完整路径(如 @"D:\CSharpTest.dll" Assembly asm = Assembly.LoadFrom(@"CSharpTest\bin\Debug\CSharpTest.dll");
LoadFile(路径) 加载指定文件(需完整路径) 文件路径(如 @"D:\CSharpTest.dll" Assembly asm = Assembly.LoadFile(@"CSharpTest.dll");
GetTypes() 获取程序集中所有类型 Type[] types = asm.GetTypes();
GetType(类名) 按类名获取程序集中的 Type(需完整命名空间) 类全名(如 "CSharpTest.TestClass" Type t = asm.GetType("CSharpTest.TestClass");
8.2.3 Activator 类:对象实例化
方法 作用 参数 示例
CreateInstance(Type) 调用无参构造实例化对象 类型 Type(如 typeof(Test) object obj = Activator.CreateInstance(t);
CreateInstance(Type, 对象数组) 调用有参构造实例化对象(参数匹配构造函数) 类型 Type,参数数组(如 new object[] { 10, "test" } object obj = Activator.CreateInstance(t, 10, "test");
CreateInstance(程序集名, 类名) 动态加载程序集并实例化对象 程序集名,类全名 object obj = Activator.CreateInstance("CSharpTest", "CSharpTest.TestClass");
8.2.4 核心操作详解(含注意事项)
  1. 构造函数调用

    • 无参构造ctor.Invoke(null)Activator.CreateInstance(t)
    • 有参构造ctor.Invoke(new object[] { 参数1, 参数2 })
    • 注意:参数类型需与构造函数匹配,否则运行时抛 TargetInvocationException
  2. 字段/属性操作

    • 读取值fieldInfo.GetValue(obj)(实例字段需传入对象实例)
    • 设置值fieldInfo.SetValue(obj, 新值)(需字段为公共或使用 BindingFlags.NonPublic
    • 私有字段:需通过 GetField("私有字段名", BindingFlags.NonPublic | BindingFlags.Instance) 获取。
  3. 方法调用

    • 实例方法methodInfo.Invoke(对象实例, 参数数组)
    • 静态方法methodInfo.Invoke(null, 参数数组)
    • 注意:参数需匹配方法签名,返回值需转换((string)method.Invoke(...))。
  4. 程序集加载

    • 路径问题LoadFrom 需完整路径(含文件名),Load 仅需程序集名(依赖 AssemblyResolve 事件)。
    • 性能:反射调用比直接调用慢约 100 倍,避免高频使用。

9.特性

分类 作用 核心成员/语法 限制/参数 典型场景
自定义特性 为程序实体(类、方法等)添加自定义元数据 - 继承 Attribute
- 命名后缀 Attribute(可省略)
- 语法:[特性名(参数)]
- 用 [AttributeUsage] 限制目标:
AttributeTargets.Class/Method/Field
- AllowMultiple=true 允许多实例
- Inherited=true 继承性
标记业务逻辑(如 [Serializable] 自定义序列化)、Unity 组件标记([RequireComponent]
过时特性 标记成员过时,提示替换方案 [Obsolete("提示信息", isError)] - isError=true 编译报错
- false 仅警告
废弃旧接口,强制迁移新方法(如 [Obsolete("Use NewMethod()", true)]
调用者信息 自动获取调用方的文件路径、行号、成员名 - [CallerFilePath]
- [CallerLineNumber]
- [CallerMemberName]
必须为参数设置默认值(如 string file = "" 日志记录、错误追踪(捕获调用位置)
条件编译 配合 #define 控制代码编译(调试/发布区分) [Conditional("符号名")](需 using System.Diagnostics 仅当符号定义时执行标记的方法 调试代码隔离(如 [Conditional("DEBUG")]
DLL 导入 调用非托管 DLL 函数(如 C++ 库) [DllImport("DLL名")](需 using System.Runtime.InteropServices - 需匹配函数签名
- extern 修饰符
调用系统 API(如 [DllImport("user32.dll")] 调用 Windows 函数)
反射获取 运行时读取特性元数据 - Type.IsDefined(typeof(特性))
- Type.GetCustomAttributes()
- 区分实例/静态成员
- 注意 BindingFlags.NonPublic 访问私有特性
框架开发(如依赖注入、AOP 拦截)

10.迭代器(Iterator)

10.1 传统实现和语法糖

分类 传统实现(接口) 语法糖(yield return
核心接口 IEnumerable(提供枚举器)
IEnumerator(遍历逻辑)
IEnumerable(仅需实现 GetEnumerator
命名空间 using System.Collections; using System.Collections;
实现复杂度 需手动实现 MoveNext()CurrentReset() 编译器自动生成迭代器逻辑(隐式实现)
核心方法 - IEnumerator GetEnumerator()
- bool MoveNext()
- object Current
- void Reset()
- IEnumerator GetEnumerator() 中使用 yield return
- 自动生成 MoveNextCurrent
适用场景 复杂遍历逻辑(如双向迭代、条件过滤) 简单顺序遍历(如数组、列表)
代码量 多行代码,显式管理光标位置(position 单行 yield return,自动维护状态
泛型支持 非泛型(object Current
需手动转型
支持泛型(配合 IEnumerable
foreach 本质 1. 调用 GetEnumerator()
2. 循环 MoveNext()
3. 取 Current
同上(编译器生成等价逻辑)
优缺点 - 灵活控制迭代状态
- 代码冗余,易出错
- 简洁易维护
- 无法直接控制底层迭代逻辑

10.2 关键对比与规则

特性 传统迭代器 yield return 迭代器
状态保存 手动维护(如 position 变量) 编译器自动保存(局部变量闭包)
遍历控制 支持中途退出、重置、逆向遍历 仅支持顺序遍历(yield 不可回退)
内存占用 即时加载所有元素 延迟加载(逐个 yield,适合大数据集)
异常处理 需手动处理 Current 越界 自动抛出 InvalidOperationException
线程安全 需手动实现同步机制 无内置线程安全(与普通遍历一致)

11 特殊语法

分类 说明 核心语法/规则 注意事项
var 隐式类型 自动推断局部变量类型 var 变量 = 初始值; - 仅用于局部变量,需初始化
- 类型固定,不可二次赋值
对象初始化 声明时直接初始化公共成员/属性 new 类型 { 成员1=值, 成员2=值 }; - 调用无参构造(可省略)
- 支持混合构造函数+初始化器(后者覆盖前者)
集合初始化 声明时填充元素 new 集合类型 { 元素1, 元素2 }; - 支持数组、ListDictionary
- 需实现 Add 方法(如 Dictionary{键, 值}
匿名类型 临时创建轻量级数据结构 var 变量 = new { 成员1=值, 成员2=值 }; - 只读成员
- 无方法,仅存储数据
可空类型 值类型支持 nullNullable 类型? 变量 = null;(如 int? a = null; - 引用类型无需加 ?
- 用 HasValue 判断空,Value 获值(需判空)
空合并操作符 空值处理简化(?? 左边值 ?? 右边值(左边为 null 时返回右边,否则左边) - 支持可空类型和引用类型
- 短路求值(右边仅在左边为 null 时执行)
内插字符串 字符串拼接简化($ $"文本{变量}文本", - 支持表达式(如 {变量.ToString()}
- 性能接近 StringBuilder
单句简略写法 省略代码块大括号(仅一句) if (条件) 语句;
for(;;) 语句;
- 仅一句代码时有效
- 避免逻辑复杂,保持可读性
属性简略写法 单行实现属性/方法(箭头语法) 属性 { get => 值; set => 逻辑; }
方法() => 表达式;
- 仅适用于简单逻辑
- 隐式 return(无返回值用 => 后接语句)

你可能感兴趣的:(c#,开发语言)