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.WriteLine
WriteLine(\"{0}\", value)
)。Console.Write
Console.ReadLine
Console.ReadKey
ConsoleKeyInfo
(可捕获键盘事件)。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
/\\0
string
(引用类型,不可变)null
2.2常量
- 声明:
const 类型 名称 = 值;
(如const float PI = 3.14f;
)。 - 特性:编译时常量,不可修改,必须初始化。
3. 转义字符
\\\'
\'Hello\'
)。\\\"
\"World\"
)。\\n
str = \"Line1\\nLine2\"
)。\\\\
C:\\\\Folder\\\\File.txt
)。\\t
Name\\tAge
)。\\b
12\\b3
→ 13
)。\\a
4. 类型转换
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条件分支
if
if (条件) { 代码 }
true
执行。if...else
if (条件) { ... } else { ... }
false
执行 else
。switch
switch (变量) { case 常量: 代码; break; }
case
需 break
(支持贯穿)。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 }
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; // 0
namespace/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
)null
null
int
、bool
、enum
、struct
int[]
、class
、object
string
new
,依赖GC(堆)new
,需StringBuilder
优化3. 字符串操作
3.1核心方法
str + str2
string.Format
str.Length
str.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.访问修饰符详解
public
private
private
protected
internal
internal
修饰的成员能在定义它的程序集(项目)内被访问,在不同程序集里无法访问,用于限制访问范围在项目内部。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) { } }
)。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. 万物之父和装箱拆箱
object
)object
是所有类型的基类,任何类型可隐式转 object
类型。ToString()
Equals()
GetHashCode()
Equals()
时通常也要重写此方法GetType()
MemberwiseClone()
ReferenceEquals()
false
object
类型)。object
类型)转原值类型,需显式转换。8. 抽象类和抽象方法、接口
8.1抽象类和抽象方法和接口使用规则
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()
string string4 = \"我是林文韬\"; int index = string4.IndexOf(\"林\"); Console.WriteLine(index); // 2
LastIndexOf()
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
数组。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]
get
和 set
字符。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. string
与 StringBuilder
对比及内存优化
string
StringBuilder
四、C#基础语法知识进阶
1.数据集合
1.1 ArrayList
不支持泛型
)using System.Collections;
ArrayList arrayList = new ArrayList();
Add
、AddRange
、Insert
删:
Remove
、RemoveAt
、Clear
查:
[]
、Contains
、IndexOf
、LastIndexOf
改:
[] =
遍历:
Count
、Capacity
、for
、foreach
1.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
、foreach
1.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
),可多个Dictionary
Dictionary
)。2.2 泛型约束(where
)关键字
where T : struct
T
必须是值类型(如int
、struct
)。class ValueHolder where T : struct { ... }
ValueHolder vh;
new()
组合(值类型默认有无参构造)。where T : class
T
必须是引用类型(如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 : 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
/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
→ IEnumerable
Action
→ Action
6.多线程基础
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反射概念和作用
程序集:编译器编译的中间产物,Windows 下为 .dll 或 .exe 文件,是代码集合
元数据:描述程序的数据,如类、函数、变量信息,存于程序集中
反射:程序运行时查看其他或自身程序集元数据,获取类、函数等信息并操作
GetType()
、typeof
关键字、Type.GetType()
方法Assembly 类:加载其他程序集,使用前需引用
System.Reflection
命名空间。加载方法有 Load
、LoadFrom
、LoadFile
Activator 类:将 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/Static
ConstructorInfo[] 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
和 Current
position
)yield return
,自动维护状态object Current
)需手动转型
IEnumerable
)GetEnumerator()
2. 循环
MoveNext()
3. 取
Current
- 代码冗余,易出错
- 无法直接控制底层迭代逻辑
10.2 关键对比与规则
yield return
迭代器position
变量)yield
不可回退)yield
,适合大数据集)Current
越界InvalidOperationException
11 特殊语法
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()}
)- 性能接近
StringBuilder
if (条件) 语句;
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)
GetAvailableThreads
out int 工作线程, out int I/O 线程
SetMaxThreads
int 工作线程最大值, int I/O 线程最大值
bool
(设置是否成功)GetMax
结果20, 20
),避免过度消耗资源导致主线程卡顿GetMaxThreads
SetMax
影响)out int 工作线程, out int I/O 线程
SetMax
SetMinThreads
int 工作线程最小值, int I/O 线程最小值
bool
(设置是否成功)GetMinThreads
SetMin
影响)out int 工作线程, out int I/O 线程
SetMin
QueueUserWorkItem
Action 任务委托, 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.ContinueWith
Task.WhenAll(Task[] tasks).ContinueWith(Task continuationAction);
Task.Factory.ContinueWhenAll
方法Task.Factory.ContinueWhenAll(Task[] tasks, Action continuationAction);
Task.WhenAny
+ Task.ContinueWith
Task.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
关键字
async
await
关键字,否则异步方法会以同步方式执行。- 异步方法名称建议以
Async
结尾。- 异步方法的返回值只能是
void
、Task
、Task
。- 异步方法中不能声明使用
ref
或 out
关键字修饰的变量。await
async
配对使用,主要作用是等待某个逻辑结束。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\";
Deconstruct
class Person { public void Deconstruct(out string n, out bool s) { ... } }
模式匹配增强
=>
代替 case:
,用 _
代替 default
public 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
、Calendar
DateTime 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\");