C#知识点入门、基础、核心、进阶_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#基础语法知识基础
- 三、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.命名参数、可选参数和动态类型
-
- 1.1.命名参数(Named Parameters)
- 1.2.可选参数(Optional Parameters)
- 1.3.动态类型(dynamic)
- 2.线程和线程池
-
- 2.1.线程基础(Thread)
- 2.2.线程池(ThreadPool)
- 3.Task任务类
-
- 3.1.Task 概述
- 3.2.Task 创建方法
- 3.3.获取返回值
- 3.4.同步执行 Task
- 3.5.任务阻塞方法
- 3.6.任务延续方法
- 3.7.取消 Task 执行方法
- 4.异步方法
-
- 4.1.同步与异步基础概念
- 4.2.异步编程适用场景
- 4.3.`async` 和 `await` 关键字
- 4.4.示例代码分析
-
- 4.4.1. 普通异步方法
- 4.4.2. 复杂逻辑计算
- 5.新增语法
-
- 5.1.C# 6 新增功能和语法
- 5.2.C# 7 新增功能和语法
- 5.3.C#8的新增功能和语法
- 5.4.C# 9 新增功能和语法
- 5.5.C#自带异常类
- 6.DateTime日期时间和TimeSpan时间跨度
-
- 6.1. DateTime
- 6.2. TimeSpan
- 7.正则表达式
知识点来源:人间自有韬哥在, 唐老狮,百度
一、C#基础语法知识入门
1. 输入输出操作
Console.WriteLineWriteLine(\"{0}\", value))。Console.WriteConsole.ReadLineConsole.ReadKeyConsoleKeyInfo(可捕获键盘事件)。2. 变量类型与常量
2.1基础类型
sbyte(8位)、short(16位)、int(32位)、long(64位)byte(8位)、ushort(16位)、uint(32位)、ulong(64位)float(单精度)、double(双精度)、decimal(高精度)bool(true/false)、char(单字符,如 \'A\')false/\\0string(引用类型,不可变)null2.2常量
- 声明:
const 类型 名称 = 值;(如const float PI = 3.14f;)。 - 特性:编译时常量,不可修改,必须初始化。
3. 转义字符
\\\'\'Hello\')。\\\"\"World\")。\\nstr = \"Line1\\nLine2\")。\\\\C:\\\\Folder\\\\File.txt)。\\tName\\tAge)。\\b12\\b3 → 13)。\\a4. 类型转换
4.1隐式转换规则
double → float → 整数(无符号/有符号) → char;decimal → 整数 → char。
(string、bool 不参与隐式转换)
4.2显式转换 API
(类型) 值(int)3.14)int.Parse(字符串)int(失败抛异常)Convert.ToInt32(值)ToString()5. 运算符
运算符分类与优先级
+ - * / %7 % 3 = 1)* / %)> 加减(+ -)= += -= *= /= %=a += 2 → a = a + 2)> = <= == !=bool(例:3 > 2 → true)! 外)! && ||&& 左假则右不执行,|| 左真则右不执行)! > && > ||& | ^ ~ <>5 << 1 = 10,5 & 3 = 1)! 例外)6. 流程控制
6.1条件分支
ifif (条件) { 代码 }true 执行。if...elseif (条件) { ... } else { ... }false 执行 else。switchswitch (变量) { case 常量: 代码; break; }case 需 break(支持贯穿)。6.2循环
whilewhile (条件) { 循环体 }do...whiledo { 循环体 } while (条件);forfor (初始; 条件; 增量) { 循环体 }6.3控制关键字
breakswitchcontinue7. 异常处理
trycatchException e 获取错误信息)。finally示例结构
try { /* 风险代码 */ }catch (Exception e) { /* 处理异常 */ }finally { /* 清理资源 */ }
二、C#基础语法知识基础
1.枚举、数组、结构体 vs 类对比
1.1枚举(Enum)
enum E_Type { A, B=5, C }E_PlayerState.Idle)E_Type var = E_Type.B;if (var == E_Type.A))(int)var字符串→枚举:
(E_Type)Enum.Parse(typeof(E_Type), \"B\")int num = (int)E_Type.A; // 0namespace/class,禁止函数内声明;避免魔数依赖int state = 0,改用枚举1.2数组(一维/二维/交错)
int[] arr = {1, 2, 3};arr[索引](0-based)arr.Length(固定)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 引用类型
null(如int=0)nullnullint、bool、enum、structint[]、class、objectstringnew,依赖GC(堆)new,需StringBuilder优化3. 字符串操作
3.1核心方法
str + str2string.Formatstr.Lengthstr.IndexOf(\"子串\")str.Substring(start, len)3.2性能优化
StringBuilder:高频拼接时使用(需using System.Text;)。- 方法:
Append()(追加)、Replace()(替换)、ToString()(转字符串)。
- 方法:
4. 函数
4.1ref & out
Swap(ref a, ref b)TryParse(out int result)4.2变长参数(params)& 默认值
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)三、C#基础语法知识核心
1、结构体与类
int=0)null(如int=0,bool=false)null(未初始化时)Point、颜色Color)Player、场景Scene)2.访问修饰符详解
publicprivateprivateprotectedinternalinternal 修饰的成员能在定义它的程序集(项目)内被访问,在不同程序集里无法访问,用于限制访问范围在项目内部。3.构造函数、析构函数和垃圾回收
规则:无返回值,函数名与类名相同,常用
public 修饰,支持重载,可用 this 指代当前对象。注意:实现有参构造会覆盖默认无参构造。
特殊用法:用
this(参数列表) 重用构造函数代码,先执行 this 后构造函数,再返回当前构造函数。语法:
~类名() { /* 代码 */ }算法:采用分代算法,分 0、1、2 代内存,新对象在 0 代,回收时先标记可达对象,再释放未标记对象并搬迁可达对象,大对象(>85000 字节)为 2 代,不搬迁压缩。
注意:GC 仅处理堆内存,引用类型堆内存由 GC 管理,值类型栈内存由系统自动管理。
手动触发:
GC.Collect();,一般在 Loading 场景时用,不常调用。4.静态成员、静态类与静态构造函数
static 修饰,属于类本身,所有实例共享,通过类名.成员直接访问(无需实例化)。Math.PI),避免重复实例化。static 修饰,仅含静态成员,不可实例化(无构造函数),强制所有成员为静态。FileHelper),提升代码规范性(如 LogHelper.Info())。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 修饰类,允许将类定义拆分到多个文件(同一命名空间)。base(参数) 调用。class Child : Parent { public Child() : base(10) { } })。virtualpublic virtual void Draw() { })。overrideoverride 重写父类 virtual 方法,实现差异化逻辑。public override void Draw() { 绘制圆形 })。basebase.成员 调用父类方法/属性,复用父类逻辑。base.Draw(); 补充子类逻辑)。sealed 修饰类,禁止被继承(密封类不能有子类)。sealed class MathHelper { })。sealed override 修饰重写方法,禁止孙类进一步重写。public sealed override void Finalize() { })。7. 万物之父和装箱拆箱
object)object 是所有类型的基类,任何类型可隐式转 object 类型。ToString()Equals()GetHashCode()Equals() 时通常也要重写此方法GetType()MemberwiseClone()ReferenceEquals()falseobject 类型)。object 类型)转原值类型,需显式转换。8. 抽象类和抽象方法、接口
8.1抽象类和抽象方法和接口使用规则
abstract 修饰,不能实例化,只能作为基类被继承。可包含抽象方法和非抽象方法、字段等。abstractabstract 修饰,无方法体,子类必须重写。abstractinterface 定义,只包含方法、属性、索引器和事件的声明,没有字段,成员默认是 public 且不能有访问修饰符,实现类必须实现所有成员。interface8.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); // 18318348848IndexOf()string string4 = \"我是林文韬\"; int index = string4.IndexOf(\"林\"); Console.WriteLine(index); // 2LastIndexOf()string string5 = \"我是林文韬林文韬\"; index = string5.LastIndexOf(\"林文韬\"); Console.WriteLine(index); // 5Remove()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); // LINWENTAOZHENDESHUAISubstring()string string9 = \"林文韬林文韬\"; string9 = string9.Substring(2); Console.WriteLine(string9); // 韬林文韬Split()string 数组。9.2. StringBuilder 常用方法
Append()stringBuilder1.Append(\"4444\"); Console.WriteLine(stringBuilder1); // 1231231234444AppendFormat()stringBuilder1.AppendFormat(\"{0}{1}\", 100, 999); Console.WriteLine(stringBuilder1); // 1231231234444100999Insert()stringBuilder1.Insert(1, \"林文\"); Console.WriteLine(stringBuilder1); // 1林文231231234444100999Remove()stringBuilder1.Remove(0, 10); Console.WriteLine(stringBuilder1); // 234444100999[index]get 和 set 字符。Console.WriteLine(stringBuilder1[1]); // 3 stringBuilder1[0] = \'A\'; Console.WriteLine(stringBuilder1); // A34444100999Replace()stringBuilder1.Replace(\"1\", \"林\"); Console.WriteLine(stringBuilder1); // A34444林00999Clear()stringBuilder1.Clear(); Console.WriteLine(stringBuilder1); // 输出空Equals()stringBuilder1.Append(\"林文真的帅\"); if (stringBuilder1.Equals(\"林文真的帅\")) { Console.WriteLine(\"相等\"); // 相等 }9.3. string 与 StringBuilder 对比及内存优化
stringStringBuilder四、C#基础语法知识进阶
1.数据集合
1.1 ArrayList
不支持泛型 )using System.Collections;ArrayList arrayList = new ArrayList();Add、AddRange、Insert删:
Remove、RemoveAt、Clear查:
[]、Contains、IndexOf、LastIndexOf改:
[] = 遍历:
Count、Capacity、for、foreach1.2 Stack
using System.Collections;Stack stack = new Stack();Push取:
Pop查:
Peek、Contains改:无(可
Clear)遍历:
Count、foreach、ToArray、while 弹栈1.3 Queue
using System.Collections;Queue queue = new Queue();Enqueue取:
Dequeue查:
Peek、Contains改:无(可
Clear)遍历:
Count、foreach、ToArray、while 出队1.4 Hashtable
不支持泛型 )using System.Collections;Hashtable hashtable = new Hashtable();Add删:
Remove、Clear查:
[]、Contains、ContainsKey、ContainsValue改:
[] = 遍历:
Count、foreach 键、foreach 值、foreach 键值对、迭代器遍历1.5 List
using System.Collections.Generic;List list = new List();Add、AddRange、Insert删:
Remove、RemoveAt、Clear查:
[]、Contains、IndexOf、LastIndexOf改:
[] = 遍历:
Count、Capacity、for、foreach1.6 Dictionary
using System.Collections.Generic;Dictionary dictionary = new Dictionary();Add删:
Remove、Clear查:
[]、ContainsKey、ContainsValue改:
[] = 遍历:
Count、foreach 键、foreach 值、foreach 键值对1.7 LinkedList
using System.Collections.Generic;LinkedList linkedList = new LinkedList();AddLast、AddFirst、AddAfter、AddBefore删:
RemoveFirst、RemoveLast、Remove查:
First、Last、Find、Contains改:修改节点
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\"); // 类型推断T、K、V),可多个DictionaryDictionary)。2.2 泛型约束(where )关键字
where T : structT 必须是值类型(如int、struct)。class ValueHolder where T : struct { ... }ValueHolder vh;new() 组合(值类型默认有无参构造)。where T : classT 必须是引用类型(如class、interface)。class RefHolder where T : class { ... }RefHolder rh;where T : IList)。where T : new()T 必须有公共无参构造函数。class Creator where T : new() { T Create() => new T(); }class 或 struct 之后(如where T : class, new())。where T : BaseClassT 必须是 BaseClass 或其子类。class ShapeHolder where T : Shape { ... }ShapeHolder sh;string)。where T : IInterfaceT 必须实现 IInterface 或其子接口。class Runner where T : IRunner { ... }Runner runner;where T : IRead, IWrite)。where T : UT 必须是另一个泛型类型 U 或其子类。class Child where T : U { ... }Child child;where T : class, new(), ILogclass/struct → new() → 接口/类)。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(无返回)Func(有返回)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();)。3.3 关键对比与最佳实践
-=精确移除。4.匿名函数 vs Lambda 表达式和闭包
4.1匿名函数 vs Lambda 表达式
delegate (参数) { 逻辑; }Action a = delegate() { Console.WriteLine(\"匿名\"); };(参数) => { 逻辑; } 或 (参数) => 表达式Func lambda = x => x.ToString();delegate,参数类型可推断(如(x) => x*2)。() => {...}单参数:
x => {...}Action noParam = () => Console.WriteLine();Func add = x => x + 1;evt += () => {...};(只能整体清空)4.2闭包(Closure)
csharp
int count = 0;
Action increment = () => count++;
increment(); // count=1
csharp
for (int i=0; i<10; i++) {
evt += () => Console.WriteLine(i); // 全部输出10
}
int index = i;保存当前值)。5.协变(Out)与逆变(In)
out(仅接口/委托泛型)in(仅接口/委托泛型)delegate T Factory();delegate void Action(T value);IEnumerable → IEnumerableAction → Action6.多线程基础
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/#elifcsharp
#if IOS
苹果逻辑
#elif ANDROID
安卓逻辑
#endif
#warning#warning \"旧版本兼容代码\"#error#error \"不支持该平台\"#region#region 初始化代码
...
#endregion8.反射
8.1反射概念和作用
程序集:编译器编译的中间产物,Windows 下为 .dll 或 .exe 文件,是代码集合
元数据:描述程序的数据,如类、函数、变量信息,存于程序集中
反射:程序运行时查看其他或自身程序集元数据,获取类、函数等信息并操作
GetType()、typeof 关键字、Type.GetType() 方法Assembly 类:加载其他程序集,使用前需引用
System.Reflection 命名空间。加载方法有 Load、LoadFrom、LoadFileActivator 类:将 Type 对象快速实例化为对象,
CreateInstance 方法可根据构造函数参数实例化对象8.2反射核心方法详解(Type/Assembly/Activator)
8.2.1 Type 类:类型元数据访问(核心)**
int a = 0; Type t = a.GetType();typeof(int))Type t = typeof(string);\"System.Int32\")Type t = Type.GetType(\"CSharpTest.TestClass\");Console.WriteLine(t.Assembly.FullName);MemberInfo[] members = t.GetMembers();BindingFlags.Public/NonPublic/Instance/StaticConstructorInfo[] ctors = t.GetConstructors();new Type[] { typeof(int) })ConstructorInfo ctor = t.GetConstructor(new Type[0]); // 无参构造FieldInfo[] fields = t.GetFields();\"j\")FieldInfo field = t.GetField(\"j\");MethodInfo[] methods = t.GetMethods();MethodInfo method = t.GetMethod(\"Speak\", Type.EmptyTypes);\"Length\")PropertyInfo prop = typeof(string).GetProperty(\"Length\");\"IEnumerable\")Type iface = t.GetInterface(\"IComparable\");8.2.2 Assembly 类:程序集加载与解析
\"CSharpTest\")Assembly asm = Assembly.Load(\"CSharpTest\");@\"D:\\CSharpTest.dll\")Assembly asm = Assembly.LoadFrom(@\"CSharpTest\\bin\\Debug\\CSharpTest.dll\");@\"D:\\CSharpTest.dll\")Assembly asm = Assembly.LoadFile(@\"CSharpTest.dll\");Type[] types = asm.GetTypes();\"CSharpTest.TestClass\")Type t = asm.GetType(\"CSharpTest.TestClass\");8.2.3 Activator 类:对象实例化
typeof(Test))object obj = Activator.CreateInstance(t);new object[] { 10, \"test\" })object obj = Activator.CreateInstance(t, 10, \"test\");object obj = Activator.CreateInstance(\"CSharpTest\", \"CSharpTest.TestClass\");8.2.4 核心操作详解(含注意事项)
-
构造函数调用
- 无参构造:
ctor.Invoke(null)或Activator.CreateInstance(t) - 有参构造:
ctor.Invoke(new object[] { 参数1, 参数2 }) - 注意:参数类型需与构造函数匹配,否则运行时抛
TargetInvocationException。
- 无参构造:
-
字段/属性操作
- 读取值:
fieldInfo.GetValue(obj)(实例字段需传入对象实例) - 设置值:
fieldInfo.SetValue(obj, 新值)(需字段为公共或使用BindingFlags.NonPublic) - 私有字段:需通过
GetField(\"私有字段名\", BindingFlags.NonPublic | BindingFlags.Instance)获取。
- 读取值:
-
方法调用
- 实例方法:
methodInfo.Invoke(对象实例, 参数数组) - 静态方法:
methodInfo.Invoke(null, 参数数组) - 注意:参数需匹配方法签名,返回值需转换(
(string)method.Invoke(...))。
- 实例方法:
-
程序集加载
- 路径问题:
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\")])[DllImport(\"DLL名\")](需 using System.Runtime.InteropServices)-
extern 修饰符[DllImport(\"user32.dll\")] 调用 Windows 函数)Type.IsDefined(typeof(特性))-
Type.GetCustomAttributes()- 注意
BindingFlags.NonPublic 访问私有特性10.迭代器(Iterator)
10.1 传统实现和语法糖
yield return)IEnumerable(提供枚举器)IEnumerator(遍历逻辑)IEnumerable(仅需实现 GetEnumerator)using System.Collections;using System.Collections;MoveNext()、Current、Reset()IEnumerator GetEnumerator()-
bool MoveNext()-
object Current-
void Reset()IEnumerator GetEnumerator() 中使用 yield return- 自动生成
MoveNext 和 Currentposition)yield return,自动维护状态object Current)需手动转型
IEnumerable)GetEnumerator()2. 循环
MoveNext()3. 取
Current- 代码冗余,易出错
- 无法直接控制底层迭代逻辑
10.2 关键对比与规则
yield return 迭代器position 变量)yield 不可回退)yield,适合大数据集)Current 越界InvalidOperationException11 特殊语法
var 隐式类型var 变量 = 初始值;- 类型固定,不可二次赋值
new 类型 { 成员1=值, 成员2=值 };- 支持混合构造函数+初始化器(后者覆盖前者)
new 集合类型 { 元素1, 元素2 };List、Dictionary等- 需实现
Add 方法(如 Dictionary 用 {键, 值})var 变量 = new { 成员1=值, 成员2=值 };- 无方法,仅存储数据
null(Nullable)类型? 变量 = null;(如 int? a = null;)?- 用
HasValue 判断空,Value 获值(需判空)??)左边值 ?? 右边值(左边为 null 时返回右边,否则左边)- 短路求值(右边仅在左边为
null 时执行)$)$\"文本{变量}文本\",{变量.ToString()})- 性能接近
StringBuilderif (条件) 语句;for(;;) 语句;- 避免逻辑复杂,保持可读性
属性 { get => 值; set => 逻辑; }方法() => 表达式;- 隐式
return(无返回值用 => 后接语句)五、C#基础语法知识补充
1.命名参数、可选参数和动态类型
1.1.命名参数(Named Parameters)
方法(参数名: 值)Debug.DrawLine(start: transform.position, end: target.position)方法(位置参数, 命名参数: 值)Raycast(origin, direction: Vector3.forward, layerMask: 1<<8)2. 自注释代码
distance 和 layerMask)1.2.可选参数(Optional Parameters)
void Method(int a = 0)void Save(string path = \"save.dat\")方法(值, 命名参数: 值)Test2(i: 1, s: \"自定义\")(跳过 bool b)- 公有方法修改默认值会破坏二进制兼容性
1.3.动态类型(dynamic)
object,但延迟绑定)dynamic obj = Activator.CreateInstance(type))dynamic dyn = GetDynamicObject();
dyn.Method();2. 动态数据处理(如 JSON 反序列化)
- 无智能提示,易拼写错误
2. 动态语言桥接(如 IronPython)
3. 反射简化
interface 或 object 替代,仅在无法避免时使用2.线程和线程池
2.1.线程基础(Thread)
Transform、GameObject)UnityMainThreadDispatcher 切换OnDestroy 中调用 Abort() 终止,否则编辑器关闭才结束2.2.线程池(ThreadPool)
GetAvailableThreadsout int 工作线程, out int I/O 线程SetMaxThreadsint 工作线程最大值, int I/O 线程最大值bool(设置是否成功)GetMax 结果20, 20),避免过度消耗资源导致主线程卡顿GetMaxThreadsSetMax 影响)out int 工作线程, out int I/O 线程SetMaxSetMinThreadsint 工作线程最小值, int I/O 线程最小值bool(设置是否成功)GetMinThreadsSetMin 影响)out int 工作线程, out int I/O 线程SetMinQueueUserWorkItemAction 任务委托, object 状态参数(可选)bool(入队是否成功)GameObject),需通过 UnityMainThreadDispatcher 切换3.Task任务类
3.1.Task 概述
Thread 的封装,一个 Task 对象可看作一个线程3.2.Task 创建方法
new Task 对象Task task = new Task(Action action); task.Start();Task task = new Task(Func function); task.Start();Start 方法Task.Run 静态方法Task task = Task.Run(Action action);Task task = Task.Run(Func function);Task.Factory.StartNew 静态方法Task task = Task.Factory.StartNew(Action action);Task task = Task.Factory.StartNew(Func function);Task.Run 类似3.3.获取返回值
Task.Result 属性T result = task.Result;3.4.同步执行 Task
Task.RunSynchronously 方法Task task = new Task(Action action); task.RunSynchronously();new Task 对象方式,Run 和 StartNew 创建时就启动,无法用于同步执行3.5.任务阻塞方法
Task.Wait 方法task.Wait();Task.WaitAny 静态方法Task.WaitAny(Task[] tasks);Task.WaitAll 静态方法Task.WaitAll(Task[] tasks);3.6.任务延续方法
Task.WhenAll + Task.ContinueWithTask.WhenAll(Task[] tasks).ContinueWith(Task continuationAction);Task.Factory.ContinueWhenAll 方法Task.Factory.ContinueWhenAll(Task[] tasks, Action continuationAction);Task.WhenAny + Task.ContinueWithTask.WhenAny(Task[] tasks).ContinueWith(Task continuationAction);Task.Factory.ContinueWhenAny 方法Task.Factory.ContinueWhenAny(Task[] tasks, Action continuationAction);3.7.取消 Task 执行方法
bool isRuning 控制线程内死循环的结束CancellationTokenSource 类Cancel 方法取消任务,Token.Register 注册取消回调4.异步方法
4.1.同步与异步基础概念
4.2.异步编程适用场景
- 复杂逻辑计算:如复杂的寻路算法,在计算过程中会消耗大量时间,使用异步编程可避免阻塞主线程。
- 网络下载、网络通讯:网络操作受网络状况影响,耗时不确定,异步执行可让主线程继续处理其他任务。
- 资源加载:如加载大型图片、音频、视频等资源,异步加载可提高程序响应速度。
4.3.async 和 await 关键字
asyncawait 关键字,否则异步方法会以同步方式执行。- 异步方法名称建议以
Async 结尾。- 异步方法的返回值只能是
void、Task、Task。- 异步方法中不能声明使用
ref 或 out 关键字修饰的变量。awaitasync 配对使用,主要作用是等待某个逻辑结束。await 关键字时,异步方法将被挂起,将控制权返回给调用者。- 当
await 修饰内容异步执行结束后,继续通过调用者线程执行后面内容。4.4.示例代码分析
4.4.1. 普通异步方法
public async void TestAsync(){ print(\"进入异步方法\"); await Task.Run(() => { print(\"异步方法Task内\"); Thread.Sleep(5000); // 在异步任务中,线程暂停5秒钟(模拟耗时操作) }); print(\"异步方法后面的逻辑\");//这句会在五秒后才打印}TestAsync();print(\"主线程逻辑执行\");
- 执行流程:调用
TestAsync方法后,打印“进入异步方法”,遇到await时,将Task.Run中的任务放入线程池执行,控制权返回给调用者,主线程继续执行“主线程逻辑执行”。5 秒后,Task.Run中的任务执行完毕,继续执行TestAsync方法中await后面的代码,打印“异步方法后面的逻辑”。
4.4.2. 复杂逻辑计算
public async void CalcPathAsync(GameObject obj, Vector3 endPos){ print(\"开始处理寻路逻辑\"); int value = 10; await Task.Run(() => { print(\"处理复杂逻辑计算\"); Thread.Sleep(1000); // 处理复杂逻辑计算,模拟耗时操作 value = 50; // 不能在多线程里访问 Unity 主线程场景中的对象 // print(obj.transform.position); }); print(\"寻路计算完毕 处理逻辑\" + value);//这句会在一秒后才打印 obj.transform.position = Vector3.zero;}CalcPathAsync(this.gameObject, Vector3.zero);
- 执行流程:调用
CalcPathAsync方法,打印“开始处理寻路逻辑”,遇到await时,将Task.Run中的任务放入线程池执行,控制权返回给调用者。1 秒后,Task.Run中的任务执行完毕,继续执行CalcPathAsync方法中await后面的代码,打印“寻路计算完毕 处理逻辑50”,并将对象的位置设置为Vector3.zero。
5.新增语法
5.1.C# 6 新增功能和语法
=> 运算符(表达式体成员)?.)null,避免 NullReferenceException 异常$)string.Format 方法using static 可以无需指定类型名称即可访问其静态成员和嵌套类型catch 语句后使用 when 关键字来筛选异常,根据不同的异常条件进行不同的处理nameof 运算符5.2.C# 7 新增功能和语法
_ 作为分隔符,方便查看数值out 参数相关和弃元知识点out 变量可直接在函数参数中声明;使用 _ 作为占位符忽略不需要的 out 参数ref 返回值5.3.C#8的新增功能和语法
static,使其不能访问上层方法变量,避免逻辑混乱public int CalcInfo(int i) { static void Calc(ref int i) { ... } ... }using() 语法简写,函数执行完自动调用对象 Dispose 方法,对象需继承 System.IDisposable 接口using StreamWriter sw = new StreamWriter(\"path\");??=string s = null; s ??= \"val\";Deconstructclass Person { public void Deconstruct(out string n, out bool s) { ... } }模式匹配增强
=> 代替 case:,用 _ 代替 defaultpublic Vector2 GetPos(PosType type) => type switch { PosType.Top_Left => new Vector2(0, 0), ... _ => new Vector2(0, 0) };变量 is {属性:值, 属性:值}DiscountInfo info = new DiscountInfo(\"5折\", true); if (info is { discount: \"6折\", isDiscount: true }) print(\"信息相同\");int ii = 10; bool bb = true; if((ii, bb) is (11, true)) { print(\"元组的值相同\"); }Deconstruct 后,可用对应类对象与元组进行 is 判断if (info is (\"5折\", true)) { print(\"位置模式 满足条件\"); }5.4.C# 9 新增功能和语法
with 表达式创建新实例public record Person(string FirstName, string LastName); var p1 = new Person(\"John\", \"Doe\"); var p2 = p1 with { LastName = \"Smith\" };if (shape is Circle { Radius: > 0 } circle) { /*... */ } switch (num) { case 0: /*... */ break; case int n when n > 0: /*... */ break; }and、or 和 not 运算符,简化复杂模式匹配if (shape is Circle { Radius: > 0 } circle and not null) { /*... */ }public interface ILogger { partial void LogHeader(); void Log(string message); } public class FileLogger : ILogger { public partial void LogHeader() { /*... */ } public void Log(string message) { /*... */ } }5.5.C#自带异常类
IndexOutOfRangeException:当一个数组的下标超出范围时运行时引发。
NullReferenceException:当一个空对象被引用时运行时引发。
ArgumentException:方法的参数是非法的
ArgumentNullException: 一个空参数传递给方法,该方法不能接受该参数
ArgumentOutOfRangeException: 参数值超出范围
SystemException:其他用户可处理的异常的基本类
OutOfMemoryException:内存空间不够
StackOverflowException:堆栈溢出
ArithmeticException:出现算术上溢或者下溢
ArrayTypeMismatchException:试图在数组中存储错误类型的对象
BadImageFormatException:图形的格式错误
DivideByZeroException:除零异常
DllNotFoundException:找不到引用的DLL
FormatException:参数格式错误
InvalidCastException:使用无效的类
InvalidOperationException:方法的调用时间错误
MethodAccessException:试图访问受保护的方法
MissingMemberException:访问一个无效版本的DLL
NotFiniteNumberException:对象不是一个有效的数字
NotSupportedException:调用的方法在类中没有实现
InvalidOperationException:当对方法的调用对对象的当前状态无效时,由某些方法引发。
6.DateTime日期时间和TimeSpan时间跨度
6.1. DateTime
System 命名空间,处理日期和时间的结构体,默认值和最小值是 0001 年 1 月 1 日 00:00:00,最大值是 9999 年 12 月 31 日 23:59:59DateTimeKind、CalendarDateTime dateTime = new DateTime(2022, 12, 1, 13, 30, 45, 500);DateTime.Now 返回当前本地日期和时间;DateTime.Today 返回今日日期;DateTime.UtcNow 返回当前 UTC 日期和时间DateTime now = DateTime.Now; DateTime today = DateTime.Today; DateTime utcNow = DateTime.UtcNow;AddDays 等方法进行时间计算DateTime newTime = now.AddDays(-1);now.ToString(\"yyyy - MM - dd - ddd / HH - mm - ss\");TryParse 转换DateTime.TryParse(\"1988/5/4 18:00:08\", out DateTime date);DateTimeOffset 获取long timestamp = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();6.2. TimeSpan
System 命名空间,时间跨度结构体,可由两个 DateTime 对象相减得到TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1);TimeSpan ts2 = new TimeSpan(1, 0, 0, 0);TimeSpan ts4 = ts2 + new TimeSpan(0, 1, 1, 1);TicksPerSecond 等常量用于计算ts4.Ticks / TimeSpan.TicksPerSecond;7.正则表达式
public bool IsMatch( string input )var regex = new Regex(@\"\\d\"); bool isMatch = regex.IsMatch(\"abc123\");public bool IsMatch( string input, int startat )var regex = new Regex(@\"\\d\"); bool isMatch = regex.IsMatch(\"abc123\", 3);public static bool IsMatch( string input, string pattern )bool isMatch = Regex.IsMatch(\"abc123\", @\"\\d\");public MatchCollection Matches( string input )var regex = new Regex(@\"\\d\"); var matches = regex.Matches(\"abc123\");public string Replace( string input, string replacement )var regex = new Regex(@\"\\d\"); string result = regex.Replace(\"abc123\", \"X\");public string[] Split( string input )var regex = new Regex(@\"\\d\"); string[] parts = regex.Split(\"abc123\");


