diff --git a/docs/cs.md b/docs/cs.md index b41f433e..5f2125ac 100644 --- a/docs/cs.md +++ b/docs/cs.md @@ -1320,6 +1320,212 @@ var result = students ```cs ["Charlie","Damon","David"] ``` +事件和委托 +---- + +> 在 .NET 中委托提供后期绑定机制。 后期绑定意味着调用方在你所创建的算法中至少提供一个方法来实现算法的一部分, 而不是在创建委托时提供完整的算法。 委托的这种特性使得 .NET 成为一种灵活、可扩展的编程环境。 + +### 定义委托类型 + +```cs +// 使用 delegate 关键字定义委托 +public delegate void MyDelegate(int x, string y); + +// 上述委托对应的函数实现应该类似: +public void MyMethod(int x, string y); +``` + +### 创建委托实例 + +```cs +// 创建委托实例 +MyDelegate myDelegate = new MyDelegate(MyMethod); +``` + +### 调用委托 + +```cs +// 调用委托,传入对应类型的参数 +myDelegate(10, "Hello"); +``` + +### 委托作为参数 + + +```cs +// 定义另一个委托类型 +public delegate int MyDelegate2(int x, int y); + +// 定义一个方法,接收委托作为参数 +public int MyMethod2(int x, int y, MyDelegate2 myDelegate) +{ + return myDelegate(x, y); +} + +// 创建委托实例 +MyDelegate2 myDelegate2 = new MyDelegate2(Add); + +// 调用 MyMethod2 方法,并传入委托作为参数 +int result = MyMethod2(10, 20, myDelegate2); +``` + +### 多播委托 + + +> 我们预先提供这些可用的方法 + +```cs +public void Sub(int x, int y) +{ + Console.WriteLine("x-y=" + (x - y)); +} + +public void Mul(int x, int y) +{ + Console.WriteLine("x*y=" + (x * y)); +} +``` + +```cs +// 定义一个委托类型 +public delegate void MyDelegate3(int x, int y); +// 定义一个方法,接收委托作为参数 +public void MyMethod3(int x, int y, MyDelegate3 myDelegate) +{ + myDelegate(x, y); +} + +// 定义另一个委托类型 +public delegate void MyDelegate4(int x, int y); +// 定义一个方法,接收委托作为参数 +public void MyMethod4(int x, int y, MyDelegate4 myDelegate) +{ + myDelegate(x, y); +} + +// 定义一个方法,接收委托作为参数 +public void MyMethod5(int x, int y, MyDelegate3 myDelegate, MyDelegate4 myDelegate2) +{ + myDelegate(x, y); + myDelegate2(x, y); +} + +// 多播委托 +MyDelegate3 myDelegate31 = new MyDelegate3(Sub); +MyDelegate4 myDelegate41 = new MyDelegate4(Mul); + +// 调用 MyMethod3 方法,并传入委托作为参数 +// output: +// x-y=5 +MyMethod3(10, 5, myDelegate31); + +// 调用 MyMethod4 方法,并传入委托作为参数 +// output: +// x*y=50 +MyMethod4(10, 5, myDelegate41); + +// 调用 MyMethod5 方法,并传入委托作为参数 +// output: +// x-y=5 +// x*y=50 +MyMethod5(10, 5, myDelegate31, myDelegate41); +``` + +### Action 委托 + +> Action 委托的变体可包含最多16个参数,返回类型为 `void` + +```cs +// 创建一个Action +public Action myAction; + +// 给Action赋值 +myAction = (x, y) => Console.WriteLine("x+y=" + (x + y)); + +// 直接调用Action +myAction(10, "Hello"); + +// 使用 null 合并运算符调用Action +myAction?.Invoke(10, "Hello"); +``` + +### Func 委托 + +> Func 委托的变体可包含最多16个参数,返回类型可以是任意类型 T + +```cs +// 创建一个Func,最后一个参数是返回类型 +public Func myFunc; + +// 给Func赋值 +myFunc = (x, y) => "x+y=" + (x + y); + +// 调用Func +string result = myFunc(10, 20); + +// 使用 null 合并运算符调用Func +string result2 = myFunc?.Invoke(10, 20); +``` + +> 和委托类似,事件是后期绑定机制。 实际上,事件是建立在对委托的语言支持之上的。事件是c#内部对委托的一种封装,它提供一种更加面向对象的编程模型和观察者模式的实现。 + +### 事件定义 + +```cs +// 使用 event 关键字定义事件 +public event EventHandler MyEvent; +``` + +### 事件订阅 + +> 我们实现定义一个方法作为事件处理器,并订阅事件 + +```cs +public void MyEventHandler(object sender, EventArgs e) +{ + // 事件处理逻辑 + // ... +} +``` + +```cs +// 订阅事件 +MyEvent += MyEventHandler; + +// 取消订阅事件 +MyEvent -= MyEventHandler; +``` + +### 事件触发 + +```cs +// 触发事件 +MyEvent?.Invoke(this, new EventArgs()); +``` + +### 事件参数 + + + +```cs +// 定义事件参数 +public class MyEventArgs : EventArgs +{ + public int Value { get; set; } +} + +// 新的Handler +public void MyEventHandler2(object sender, MyEventArgs e) +{ + // 事件处理逻辑,这里可以获取到事件参数 + Console.WriteLine("事件参数的值:" + e.Value); +} + +// 触发事件 +// output: +// 事件参数的值:10 +MyEvent?.Invoke(this, new MyEventArgs { Value = 10 }); +``` 语法糖 ----