跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
最近更改
随机页面
MediaWiki帮助
代码酷
搜索
搜索
中文(中国大陆)
外观
创建账号
登录
个人工具
创建账号
登录
未登录编辑者的页面
了解详情
贡献
讨论
编辑“︁
C Sharp 委托与事件
”︁(章节)
页面
讨论
大陆简体
阅读
编辑
编辑源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
编辑
编辑源代码
查看历史
常规
链入页面
相关更改
特殊页面
页面信息
外观
移至侧栏
隐藏
您的更改会在有权核准的用户核准后向读者展示。
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
= C#委托与事件 = == 介绍 == '''委托(Delegate)'''和'''事件(Event)'''是C#中实现回调机制和发布-订阅模式的核心概念。委托是一种类型安全的函数指针,允许将方法作为参数传递或存储;事件是基于委托的封装,提供了一种安全的方式来实现观察者模式。理解这两个概念对于开发响应式、松耦合的应用程序至关重要。 === 核心概念 === * '''委托''':定义方法签名,可以指向任何匹配签名的方法。 * '''事件''':是委托的封装,限制外部直接操作,仅允许添加/移除订阅者。 == 委托详解 == === 委托声明与使用 === 委托通过<code>delegate</code>关键字声明,指定方法的返回类型和参数列表。 <syntaxhighlight lang="csharp"> // 声明一个委托类型 public delegate void PrintMessage(string message); class Program { // 匹配委托签名的方法 static void DisplayMessage(string text) { Console.WriteLine($"Message: {text}"); } static void Main() { // 实例化委托并绑定方法 PrintMessage printer = DisplayMessage; printer("Hello, Delegate!"); // 调用委托 } } </syntaxhighlight> '''输出:''' <pre> Message: Hello, Delegate! </pre> === 多播委托 === 委托支持多播(组合多个方法),通过<code>+=</code>和<code>-=</code>操作符管理调用列表。 <syntaxhighlight lang="csharp"> PrintMessage multiPrinter = DisplayMessage; multiPrinter += (string msg) => Console.WriteLine($"Upper: {msg.ToUpper()}"); multiPrinter("Multi-cast"); </syntaxhighlight> '''输出:''' <pre> Message: Multi-cast Upper: MULTI-CAST </pre> == 事件详解 == 事件是委托的封装,仅允许在声明类内触发,外部只能订阅/取消订阅。 === 标准事件模式 === 使用<code>EventHandler</code>委托和继承自<code>EventArgs</code>的参数类。 <syntaxhighlight lang="csharp"> public class TemperatureChangedEventArgs : EventArgs { public double NewTemperature { get; set; } } public class Thermostat { // 1. 定义事件 public event EventHandler<TemperatureChangedEventArgs> TemperatureChanged; // 2. 触发事件的方法 protected virtual void OnTemperatureChanged(double temp) { TemperatureChanged?.Invoke(this, new TemperatureChangedEventArgs { NewTemperature = temp }); } public void SimulateChange(double newTemp) { OnTemperatureChanged(newTemp); } } class Program { static void Main() { Thermostat thermostat = new Thermostat(); // 3. 订阅事件 thermostat.TemperatureChanged += (sender, e) => Console.WriteLine($"Temperature now: {e.NewTemperature}°C"); thermostat.SimulateChange(23.5); } } </syntaxhighlight> '''输出:''' <pre> Temperature now: 23.5°C </pre> === 自定义委托事件 === 不使用<code>EventHandler</code>模板时: <syntaxhighlight lang="csharp"> public delegate void AlertHandler(string message); public class SecuritySystem { public event AlertHandler IntrusionDetected; public void DetectMotion() { IntrusionDetected?.Invoke("Motion detected at " + DateTime.Now); } } </syntaxhighlight> == 实际应用案例 == === UI开发中的按钮点击 === 在WPF或WinForms中,按钮点击通过事件处理: <syntaxhighlight lang="csharp"> button.Click += (sender, e) => { MessageBox.Show("Button clicked!"); }; </syntaxhighlight> === 观察者模式实现 === <mermaid> classDiagram class Subject { +Attach(Observer o) +Detach(Observer o) +Notify() } class ConcreteSubject { -state +GetState() +SetState() } class Observer { <<interface>> +Update() } class ConcreteObserver { +Update() } Subject <|-- ConcreteSubject Observer <|-- ConcreteObserver ConcreteSubject o-- Observer </mermaid> == 高级主题 == === 协变与逆变(C# 4.0+) === 委托支持泛型类型参数的变体: * '''协变(out)''':允许返回派生程度更大的类型 * '''逆变(in)''':允许参数接受派生程度更小的类型 <math> \text{协变:} \ \ \ \ Func<Animal> \rightarrow Func<Dog> \\ \text{逆变:} \ \ \ \ Action<Dog> \rightarrow Action<Animal> </math> === 异步事件 === 使用<code>async/await</code>处理耗时事件: <syntaxhighlight lang="csharp"> thermostat.TemperatureChanged += async (sender, e) => { await Task.Delay(1000); Console.WriteLine($"Async handling: {e.NewTemperature}"); }; </syntaxhighlight> == 常见问题 == {| class="wikitable" |- ! 问题 !! 解决方案 |- | 事件触发为<code>null</code> || 使用<code>?.Invoke()</code>空值检查 |- | 内存泄漏 || 及时取消订阅(<code>-=</code>) |- | 多线程竞争 || 缓存委托引用后调用 |} == 总结 == * 委托是类型安全的回调机制 * 事件是受限的委托,用于实现发布-订阅 * 标准模式使用<code>EventHandler<TEventArgs></code> * 实际应用于UI交互、观察者模式等场景 [[Category:编程语言]] [[Category:C Sharp]] [[Category:C Sharp 属性与事件]]
摘要:
请注意,所有对代码酷的贡献均被视为依照知识共享署名-非商业性使用-相同方式共享发表(详情请见
代码酷:著作权
)。如果您不希望您的文字作品被随意编辑和分发传播,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)