C#笔记更新
This commit is contained in:
Vendored
+1
-3
@@ -1,3 +1 @@
|
||||
{
|
||||
"alwaysUpdateLinks": true
|
||||
}
|
||||
{}
|
||||
@@ -0,0 +1,467 @@
|
||||
# 事件
|
||||
概念:
|
||||
事件是==基于委托的安全封装==
|
||||
它用于表示“某件事发生了”,并通知订阅这个事件的方法
|
||||
|
||||
简单理解:
|
||||
委托像一个可以直接调用的方法列表
|
||||
事件像一个“通知开关”
|
||||
类外部可以订阅通知,但不能随意触发通知
|
||||
|
||||
作用:
|
||||
1. 当某个状态变化时通知其他对象
|
||||
2. 降低对象之间的耦合
|
||||
3. 保护委托,避免类外部随意赋值或调用
|
||||
4. 常用于按钮点击、游戏状态变化、网络消息、任务完成等场景
|
||||
|
||||
关键字:
|
||||
```csharp
|
||||
event
|
||||
```
|
||||
|
||||
----
|
||||
# 和委托的关系
|
||||
事件的底层是委托:
|
||||
|
||||
```csharp
|
||||
public event Action OnFinished;
|
||||
```
|
||||
|
||||
这里:
|
||||
`Action` 是委托类型
|
||||
`OnFinished` 是事件名
|
||||
|
||||
可以和[[委托]]一起理解:
|
||||
委托负责“存方法和调用方法”
|
||||
事件负责“安全地把通知发布给外部”
|
||||
|
||||
----
|
||||
# 委托和事件的区别
|
||||
直接公开委托:
|
||||
```csharp
|
||||
public Action OnFinished;
|
||||
```
|
||||
|
||||
类外部可以:
|
||||
```csharp
|
||||
task.OnFinished = null;
|
||||
task.OnFinished?.Invoke();
|
||||
```
|
||||
|
||||
问题:
|
||||
外部可以清空委托
|
||||
外部也可以擅自触发通知
|
||||
|
||||
使用事件:
|
||||
```csharp
|
||||
public event Action OnFinished;
|
||||
```
|
||||
|
||||
类外部只能:
|
||||
```csharp
|
||||
task.OnFinished += ShowMessage;
|
||||
task.OnFinished -= ShowMessage;
|
||||
```
|
||||
|
||||
类外部不能:
|
||||
```csharp
|
||||
// task.OnFinished = null;
|
||||
// task.OnFinished?.Invoke();
|
||||
```
|
||||
|
||||
说明:
|
||||
事件让“触发通知”的控制权保留在声明事件的类内部
|
||||
|
||||
----
|
||||
# 语法
|
||||
声明事件:
|
||||
```csharp
|
||||
访问修饰符 event 委托类型 事件名;
|
||||
```
|
||||
|
||||
使用自定义委托:
|
||||
```csharp
|
||||
public delegate void FinishHandler();
|
||||
|
||||
public event FinishHandler OnFinished;
|
||||
```
|
||||
|
||||
使用 `Action`:
|
||||
```csharp
|
||||
public event Action OnFinished;
|
||||
```
|
||||
|
||||
使用 `EventHandler`:
|
||||
```csharp
|
||||
public event EventHandler OnFinished;
|
||||
```
|
||||
|
||||
----
|
||||
# 基础案例
|
||||
```csharp
|
||||
using System;
|
||||
|
||||
class TaskRunner
|
||||
{
|
||||
public event Action OnFinished;
|
||||
|
||||
public void Run()
|
||||
{
|
||||
Console.WriteLine("任务执行中");
|
||||
Console.WriteLine("任务完成");
|
||||
|
||||
OnFinished?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
static void ShowMessage()
|
||||
{
|
||||
Console.WriteLine("收到任务完成通知");
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
TaskRunner task = new TaskRunner();
|
||||
task.OnFinished += ShowMessage;
|
||||
|
||||
task.Run();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
输出:
|
||||
```text
|
||||
任务执行中
|
||||
任务完成
|
||||
收到任务完成通知
|
||||
```
|
||||
|
||||
理解:
|
||||
1. `TaskRunner` 负责执行任务
|
||||
2. 任务完成后,在类内部触发 `OnFinished`
|
||||
3. `ShowMessage` 订阅了事件
|
||||
4. 所以任务完成时,会自动执行 `ShowMessage`
|
||||
|
||||
----
|
||||
# 订阅和取消订阅
|
||||
订阅事件:
|
||||
```csharp
|
||||
task.OnFinished += ShowMessage;
|
||||
```
|
||||
|
||||
取消订阅:
|
||||
```csharp
|
||||
task.OnFinished -= ShowMessage;
|
||||
```
|
||||
|
||||
说明:
|
||||
1. `+=` 表示订阅事件
|
||||
2. `-=` 表示取消订阅
|
||||
3. 可以有多个方法订阅同一个事件
|
||||
4. 取消订阅时,方法必须和订阅时是同一个方法
|
||||
|
||||
----
|
||||
# 一个事件可以有多个订阅者
|
||||
```csharp
|
||||
using System;
|
||||
|
||||
class TaskRunner
|
||||
{
|
||||
public event Action OnFinished;
|
||||
|
||||
public void Run()
|
||||
{
|
||||
Console.WriteLine("任务完成");
|
||||
OnFinished?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
static void ShowMessage()
|
||||
{
|
||||
Console.WriteLine("显示完成提示");
|
||||
}
|
||||
|
||||
static void SaveRecord()
|
||||
{
|
||||
Console.WriteLine("保存完成记录");
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
TaskRunner task = new TaskRunner();
|
||||
|
||||
task.OnFinished += ShowMessage;
|
||||
task.OnFinished += SaveRecord;
|
||||
|
||||
task.Run();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
输出:
|
||||
```text
|
||||
任务完成
|
||||
显示完成提示
|
||||
保存完成记录
|
||||
```
|
||||
|
||||
理解:
|
||||
同一个事件可以通知多个订阅者
|
||||
每个订阅的方法都会被依次调用
|
||||
|
||||
----
|
||||
# 触发事件时要判空
|
||||
不安全写法:
|
||||
```csharp
|
||||
OnFinished();
|
||||
```
|
||||
|
||||
问题:
|
||||
如果没有任何方法订阅事件
|
||||
`OnFinished` 就可能为 `null`
|
||||
直接调用会报错
|
||||
|
||||
常见写法:
|
||||
```csharp
|
||||
if (OnFinished != null)
|
||||
{
|
||||
OnFinished();
|
||||
}
|
||||
```
|
||||
|
||||
更简洁的写法:
|
||||
```csharp
|
||||
OnFinished?.Invoke();
|
||||
```
|
||||
|
||||
说明:
|
||||
`?.Invoke()` 表示事件不为 `null` 时才调用
|
||||
|
||||
----
|
||||
# 带参数的事件
|
||||
事件可以使用带参数的 `Action`:
|
||||
|
||||
```csharp
|
||||
using System;
|
||||
|
||||
class ScoreSystem
|
||||
{
|
||||
public event Action<int> OnScoreChanged;
|
||||
|
||||
public void AddScore(int score)
|
||||
{
|
||||
OnScoreChanged?.Invoke(score);
|
||||
}
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
static void ShowScore(int score)
|
||||
{
|
||||
Console.WriteLine("获得分数:" + score);
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
ScoreSystem system = new ScoreSystem();
|
||||
system.OnScoreChanged += ShowScore;
|
||||
|
||||
system.AddScore(100);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
输出:
|
||||
```text
|
||||
获得分数:100
|
||||
```
|
||||
|
||||
说明:
|
||||
`Action<int>` 表示订阅方法需要接收一个 `int` 参数
|
||||
|
||||
----
|
||||
# EventHandler 标准写法
|
||||
在 .NET 中,事件常使用 `EventHandler`:
|
||||
|
||||
```csharp
|
||||
using System;
|
||||
|
||||
class TaskRunner
|
||||
{
|
||||
public event EventHandler Finished;
|
||||
|
||||
public void Run()
|
||||
{
|
||||
Console.WriteLine("任务完成");
|
||||
Finished?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
static void OnTaskFinished(object sender, EventArgs e)
|
||||
{
|
||||
Console.WriteLine("收到任务完成通知");
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
TaskRunner task = new TaskRunner();
|
||||
task.Finished += OnTaskFinished;
|
||||
|
||||
task.Run();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
1. `sender` 表示触发事件的对象
|
||||
2. `EventArgs.Empty` 表示没有额外事件数据
|
||||
3. `EventHandler` 是 .NET 中常见的事件委托类型
|
||||
|
||||
----
|
||||
# EventHandler<TEventArgs>
|
||||
如果事件需要传更多信息,可以自定义事件参数类:
|
||||
|
||||
```csharp
|
||||
using System;
|
||||
|
||||
class ScoreChangedEventArgs : EventArgs
|
||||
{
|
||||
public int Score { get; }
|
||||
|
||||
public ScoreChangedEventArgs(int score)
|
||||
{
|
||||
Score = score;
|
||||
}
|
||||
}
|
||||
|
||||
class ScoreSystem
|
||||
{
|
||||
public event EventHandler<ScoreChangedEventArgs> ScoreChanged;
|
||||
|
||||
public void AddScore(int score)
|
||||
{
|
||||
ScoreChanged?.Invoke(this, new ScoreChangedEventArgs(score));
|
||||
}
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
static void OnScoreChanged(object sender, ScoreChangedEventArgs e)
|
||||
{
|
||||
Console.WriteLine("获得分数:" + e.Score);
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
ScoreSystem system = new ScoreSystem();
|
||||
system.ScoreChanged += OnScoreChanged;
|
||||
|
||||
system.AddScore(100);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
输出:
|
||||
```text
|
||||
获得分数:100
|
||||
```
|
||||
|
||||
理解:
|
||||
`ScoreChangedEventArgs` 专门用来保存事件附带的数据
|
||||
订阅方法通过 `e.Score` 获取具体信息
|
||||
|
||||
----
|
||||
# 推荐的触发方式
|
||||
事件一般由声明它的类负责触发:
|
||||
|
||||
```csharp
|
||||
class TaskRunner
|
||||
{
|
||||
public event EventHandler Finished;
|
||||
|
||||
protected virtual void OnFinished()
|
||||
{
|
||||
Finished?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
Console.WriteLine("任务完成");
|
||||
OnFinished();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
好处:
|
||||
1. 把“触发事件”的代码集中在 `OnFinished`
|
||||
2. 子类可以通过重写 `OnFinished` 扩展行为
|
||||
3. 事件命名和触发逻辑更清晰
|
||||
|
||||
----
|
||||
# 常见使用场景
|
||||
1. 按钮点击后通知界面逻辑
|
||||
2. 任务完成后刷新状态
|
||||
3. 分数、血量、进度变化后更新显示
|
||||
4. 网络消息到达后通知处理模块
|
||||
5. 下载完成、计时结束、加载完成等通知
|
||||
|
||||
----
|
||||
# 注意
|
||||
1. 事件的底层是委托
|
||||
2. 事件只能声明在类、结构体或接口中
|
||||
3. 类外部只能使用 `+=` 订阅、`-=` 取消订阅
|
||||
4. 类外部不能直接赋值事件,也不能直接触发事件
|
||||
5. 事件可能没有订阅者,触发前要判空
|
||||
6. 简单事件可用 `Action`
|
||||
7. 标准 .NET 事件常用 `EventHandler` 或 `EventHandler<TEventArgs>`
|
||||
8. 不再需要监听时,应及时取消订阅
|
||||
|
||||
----
|
||||
# 易错点
|
||||
1. 事件不是独立机制,它本质上依赖委托
|
||||
2. `event` 不能让外部直接调用,只能让声明类内部触发
|
||||
3. `+=` 是订阅,不是普通赋值
|
||||
4. 事件没有订阅者时,直接调用可能出现空引用异常
|
||||
5. 订阅后忘记 `-=`,可能导致对象一直被引用
|
||||
|
||||
错误示例:
|
||||
```csharp
|
||||
TaskRunner task = new TaskRunner();
|
||||
|
||||
// task.OnFinished?.Invoke();
|
||||
// task.OnFinished = null;
|
||||
```
|
||||
|
||||
原因:
|
||||
`OnFinished` 是事件
|
||||
外部只能订阅或取消订阅,不能触发或覆盖它
|
||||
|
||||
----
|
||||
# 一句话记忆
|
||||
==事件是对委托的安全封装,用来在事情发生时通知订阅者。==
|
||||
|
||||
----
|
||||
# 面试/复习时怎么说
|
||||
可以这样答:
|
||||
|
||||
“事件本质上是对委托的封装,用于发布通知。
|
||||
外部对象可以通过 `+=` 订阅事件、通过 `-=` 取消订阅,但不能直接触发或覆盖事件。
|
||||
这样可以把触发权保留在事件发布者内部,常用于按钮点击、状态变化和任务完成等场景。”
|
||||
|
||||
----
|
||||
引用:
|
||||
1. Microsoft Learn: [Events](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/events/)
|
||||
2. Microsoft Learn: [EventHandler Delegate](https://learn.microsoft.com/en-us/dotnet/api/system.eventhandler)
|
||||
3. Microsoft Learn: [EventHandler<TEventArgs> Delegate](https://learn.microsoft.com/en-us/dotnet/api/system.eventhandler-1)
|
||||
|
||||
#事件
|
||||
#event
|
||||
#委托
|
||||
#EventHandler
|
||||
#进阶
|
||||
@@ -0,0 +1,426 @@
|
||||
# 委托
|
||||
概念:
|
||||
委托是==可以引用方法的类型==
|
||||
可以理解为“函数的容器”或“存方法的变量”
|
||||
|
||||
作用:
|
||||
1. 把方法赋值给变量
|
||||
2. 把方法作为参数传递
|
||||
3. 让一个地方可以调用多个方法
|
||||
4. 为事件、匿名函数、lambda 提供基础
|
||||
|
||||
简单理解:
|
||||
普通变量存数据
|
||||
委托变量存“符合条件的方法”
|
||||
|
||||
----
|
||||
# 通常用法
|
||||
1. 作为类的成员,保存回调方法
|
||||
2. 作为方法参数,让调用者决定具体执行什么逻辑
|
||||
3. 同时绑定多个方法,实现多播调用
|
||||
4. 配合 `Action`、`Func`、匿名函数和 lambda 使用
|
||||
|
||||
实际开发中:
|
||||
自定义委托仍然会用到
|
||||
但很多简单场景更常使用系统自带的 `Action` 和 `Func`
|
||||
|
||||
----
|
||||
# 语法
|
||||
关键字:
|
||||
```csharp
|
||||
delegate
|
||||
```
|
||||
|
||||
定义委托:
|
||||
```csharp
|
||||
访问修饰符 delegate 返回值类型 委托名(参数列表);
|
||||
```
|
||||
|
||||
示例:
|
||||
```csharp
|
||||
public delegate void MyDelegate(string message);
|
||||
```
|
||||
|
||||
说明:
|
||||
`MyDelegate` 只能保存:
|
||||
参数是 `string`
|
||||
返回值是 `void`
|
||||
的方法
|
||||
|
||||
----
|
||||
# 基础案例
|
||||
```csharp
|
||||
using System;
|
||||
|
||||
public delegate void MyDelegate(string message);
|
||||
|
||||
class Program
|
||||
{
|
||||
static void PrintMessage(string message)
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
MyDelegate del = PrintMessage;
|
||||
del("你好,委托");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
输出:
|
||||
```text
|
||||
你好,委托
|
||||
```
|
||||
|
||||
理解:
|
||||
1. `MyDelegate` 规定了方法的格式
|
||||
2. `PrintMessage` 的参数和返回值符合这个格式
|
||||
3. 所以可以赋值给 `del`
|
||||
4. 调用 `del(...)`,本质上就是调用 `PrintMessage(...)`
|
||||
|
||||
----
|
||||
# 方法必须匹配委托格式
|
||||
```csharp
|
||||
public delegate int Calculate(int a, int b);
|
||||
|
||||
static int Add(int a, int b)
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
|
||||
Calculate calculate = Add;
|
||||
Console.WriteLine(calculate(10, 20));
|
||||
```
|
||||
|
||||
正确匹配:
|
||||
参数数量一致
|
||||
参数类型一致
|
||||
返回值类型一致
|
||||
|
||||
错误示例:
|
||||
```csharp
|
||||
static void Print(int a, int b)
|
||||
{
|
||||
}
|
||||
|
||||
// Calculate calculate = Print;
|
||||
```
|
||||
|
||||
原因:
|
||||
`Calculate` 要求返回 `int`
|
||||
`Print` 的返回值是 `void`
|
||||
两者不匹配
|
||||
|
||||
----
|
||||
# 委托的赋值和调用
|
||||
赋值:
|
||||
```csharp
|
||||
MyDelegate del = PrintMessage;
|
||||
```
|
||||
|
||||
调用:
|
||||
```csharp
|
||||
del("hello");
|
||||
```
|
||||
|
||||
也可以使用 `Invoke`:
|
||||
```csharp
|
||||
del.Invoke("hello");
|
||||
```
|
||||
|
||||
通常写法:
|
||||
直接写 `del(...)` 更常见
|
||||
`Invoke(...)` 的语义更明确
|
||||
|
||||
----
|
||||
# 委托可以作为参数
|
||||
作用:
|
||||
把“具体要做什么”交给调用者决定
|
||||
|
||||
```csharp
|
||||
using System;
|
||||
|
||||
public delegate void HandleNumber(int number);
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Process(int number, HandleNumber handler)
|
||||
{
|
||||
handler(number);
|
||||
}
|
||||
|
||||
static void PrintNumber(int number)
|
||||
{
|
||||
Console.WriteLine("数字:" + number);
|
||||
}
|
||||
|
||||
static void PrintDouble(int number)
|
||||
{
|
||||
Console.WriteLine("两倍:" + number * 2);
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Process(10, PrintNumber);
|
||||
Process(10, PrintDouble);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
输出:
|
||||
```text
|
||||
数字:10
|
||||
两倍:20
|
||||
```
|
||||
|
||||
理解:
|
||||
`Process` 不关心具体处理方式
|
||||
只要求传进来的方法符合 `HandleNumber` 的格式
|
||||
|
||||
----
|
||||
# 多播委托
|
||||
一个委托变量可以同时绑定多个方法:
|
||||
|
||||
```csharp
|
||||
using System;
|
||||
|
||||
public delegate void MyDelegate();
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Method1()
|
||||
{
|
||||
Console.WriteLine("执行方法1");
|
||||
}
|
||||
|
||||
static void Method2()
|
||||
{
|
||||
Console.WriteLine("执行方法2");
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
MyDelegate del = Method1;
|
||||
del += Method2;
|
||||
|
||||
del();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
输出:
|
||||
```text
|
||||
执行方法1
|
||||
执行方法2
|
||||
```
|
||||
|
||||
取消绑定:
|
||||
```csharp
|
||||
del -= Method2;
|
||||
```
|
||||
|
||||
说明:
|
||||
1. `+=` 用来添加方法
|
||||
2. `-=` 用来移除方法
|
||||
3. 调用时会按添加顺序依次执行
|
||||
4. 多播委托最适合返回值为 `void` 的情况
|
||||
|
||||
----
|
||||
# 有返回值的多播委托
|
||||
```csharp
|
||||
public delegate int Calculate();
|
||||
|
||||
static int Method1()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Method2()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
Calculate calculate = Method1;
|
||||
calculate += Method2;
|
||||
|
||||
int result = calculate();
|
||||
Console.WriteLine(result);
|
||||
```
|
||||
|
||||
输出:
|
||||
```text
|
||||
2
|
||||
```
|
||||
|
||||
说明:
|
||||
两个方法都会执行
|
||||
但委托调用的最终返回值,只会保留最后一个方法的返回值
|
||||
|
||||
所以:
|
||||
多播委托通常更适合 `void` 返回值
|
||||
|
||||
----
|
||||
# 空委托要先判断
|
||||
错误示例:
|
||||
```csharp
|
||||
MyDelegate del = null;
|
||||
|
||||
// del();
|
||||
```
|
||||
|
||||
原因:
|
||||
委托变量是引用类型
|
||||
没有绑定方法时可能为 `null`
|
||||
|
||||
常见写法:
|
||||
```csharp
|
||||
if (del != null)
|
||||
{
|
||||
del();
|
||||
}
|
||||
```
|
||||
|
||||
更简洁的写法:
|
||||
```csharp
|
||||
del?.Invoke();
|
||||
```
|
||||
|
||||
说明:
|
||||
`?.` 会先判断 `del` 是否为 `null`
|
||||
不为 `null` 才调用 `Invoke()`
|
||||
|
||||
----
|
||||
# Action
|
||||
`Action` 是系统自带的委托类型:
|
||||
==无返回值==
|
||||
|
||||
无参:
|
||||
```csharp
|
||||
Action action = PrintHello;
|
||||
action();
|
||||
|
||||
static void PrintHello()
|
||||
{
|
||||
Console.WriteLine("Hello");
|
||||
}
|
||||
```
|
||||
|
||||
有参数:
|
||||
```csharp
|
||||
Action<string> print = PrintMessage;
|
||||
print("你好");
|
||||
|
||||
static void PrintMessage(string message)
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
`Action` 后面的泛型参数表示方法参数类型
|
||||
它的返回值始终是 `void`
|
||||
|
||||
----
|
||||
# Func
|
||||
`Func` 是系统自带的泛型委托类型:
|
||||
==有返回值==
|
||||
|
||||
```csharp
|
||||
Func<int, int, int> add = Add;
|
||||
|
||||
int result = add(10, 20);
|
||||
Console.WriteLine(result);
|
||||
|
||||
static int Add(int a, int b)
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
```csharp
|
||||
Func<参数1类型, 参数2类型, 返回值类型>
|
||||
```
|
||||
|
||||
上面的:
|
||||
```csharp
|
||||
Func<int, int, int>
|
||||
```
|
||||
|
||||
表示:
|
||||
前两个 `int` 是参数类型
|
||||
最后一个 `int` 是返回值类型
|
||||
|
||||
----
|
||||
# 自定义委托、Action、Func 的区别
|
||||
| 对比点 | 自定义委托 | `Action` | `Func` |
|
||||
|---|---|---|---|
|
||||
| 是否需要自己声明 | 需要 | 不需要 | 不需要 |
|
||||
| 返回值 | 自己定义 | 必须是 `void` | 必须有返回值 |
|
||||
| 参数 | 自己定义 | 可有多个 | 可有多个 |
|
||||
| 常见用途 | 语义明确的回调 | 简单无返回值操作 | 简单有返回值操作 |
|
||||
|
||||
实际使用建议:
|
||||
1. 简单无返回值回调,优先考虑 `Action`
|
||||
2. 简单有返回值回调,优先考虑 `Func`
|
||||
3. 需要清晰业务语义时,可以定义自己的委托类型
|
||||
|
||||
----
|
||||
# 和事件的关系
|
||||
委托:
|
||||
可以在类外部赋值
|
||||
也可以在类外部直接调用
|
||||
|
||||
事件:
|
||||
是对委托的进一步封装
|
||||
类外部只能订阅和取消订阅
|
||||
不能直接调用事件
|
||||
|
||||
可以和[[事件]]一起理解:
|
||||
委托负责“存方法和调用方法”
|
||||
事件负责“更安全地对外发布通知”
|
||||
|
||||
----
|
||||
# 注意
|
||||
1. 委托是一种引用类型
|
||||
2. 委托变量只能保存签名匹配的方法
|
||||
3. 签名主要看参数和返回值
|
||||
4. 委托可以绑定一个或多个方法
|
||||
5. `+=` 添加方法,`-=` 移除方法
|
||||
6. 调用可能为 `null` 的委托前要先判断
|
||||
7. `Action` 无返回值,`Func` 有返回值
|
||||
8. 自定义委托不能只靠返回值不同来重名
|
||||
|
||||
----
|
||||
# 易错点
|
||||
1. 委托不是方法本身,而是“引用方法的变量”
|
||||
2. 委托类型和方法签名不匹配时,不能赋值
|
||||
3. `Add` 和 `+=` 不一样,委托绑定方法用 `+=`
|
||||
4. 多播委托有返回值时,只能拿到最后一个方法的返回值
|
||||
5. `del?.Invoke()` 可以避免空引用异常
|
||||
|
||||
----
|
||||
# 一句话记忆
|
||||
==委托就是一种可以存方法、传方法、调方法的类型。==
|
||||
|
||||
----
|
||||
# 面试/复习时怎么说
|
||||
可以这样答:
|
||||
|
||||
“委托是一种引用方法的类型,可以把符合指定签名的方法赋值给委托变量,再通过委托统一调用。
|
||||
它可以作为参数传递,也可以绑定多个方法,常用于回调和事件机制。
|
||||
实际开发中,简单场景通常使用系统自带的 `Action` 和 `Func`。”
|
||||
|
||||
----
|
||||
引用:
|
||||
1. Microsoft Learn: [Delegates](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/)
|
||||
2. Microsoft Learn: [Action Delegate](https://learn.microsoft.com/en-us/dotnet/api/system.action)
|
||||
3. Microsoft Learn: [Func Delegate](https://learn.microsoft.com/en-us/dotnet/api/system.func-2)
|
||||
|
||||
#委托
|
||||
#delegate
|
||||
#Action
|
||||
#Func
|
||||
#进阶
|
||||
+2
-2
@@ -37,10 +37,10 @@
|
||||
5. [[泛型]]和[[泛型约束]]
|
||||
6. [[List]]
|
||||
7. [[Dictionary]]
|
||||
8. 顺序存储和链式存储
|
||||
8. [[顺序存储和链式存储]]
|
||||
9. LinkedList
|
||||
10. 泛型栈和队列
|
||||
11. 委托事件
|
||||
11. [[委托]]和[[事件]]
|
||||
12. 匿名函数
|
||||
13. lambda
|
||||
14. List排序
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# netstat \[-anp] \[| grep 端口号]
|
||||
|
||||
**略过时,推荐使用ss(同参数)**
|
||||
**过时,推荐使用ss(同参数)**
|
||||
|
||||
作用:查看端口的占用情况
|
||||
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
- b:后台下载,会在当前工作目录下写wget-log日志
|
||||
|
||||
示例:
|
||||
- apache-
|
||||
-
|
||||
@@ -1,2 +1,2 @@
|
||||
相关指令:chmod
|
||||
相关指令:[[chmod&chown]]
|
||||
前提:文件或文件夹的所属用户或root用户
|
||||
Reference in New Issue
Block a user