事件
作者:追风剑情 发布于:2021-1-12 16:07 分类:C#
示例一:自定义事件类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp16 { class Program { //EventHandler已在System命名空间中定义,这里直接使用。 public event EventHandler RaiseEvent; //使用EventHandler的泛型版本,发布自定义事件参数。 public event EventHandler<CustomEventArgs> RaiseCustomEvent1; //直接声明自定义事件与上面的泛型版本等价 public event CustomEventHandler RaiseCustomEvent2; static void Main(string[] args) { var pub = new Publisher(); var sub1 = new Subscriber("sub1", pub); var sub2 = new Subscriber("sub2", pub); pub.DoSomething(); Console.WriteLine("Press any key to continue..."); Console.ReadLine(); } //事件发布者 public class Publisher { public event EventHandler<CustomEventArgs> RaiseCustomEvent; public void DoSomething() { OnRaiseCustomEvent(new CustomEventArgs("Event triggered")); } protected virtual void OnRaiseCustomEvent(CustomEventArgs e) { EventHandler<CustomEventArgs> raiseEvent = RaiseCustomEvent; if (raiseEvent != null) { e.Message += $" at {DateTime.Now}"; //raiseEvent(this, e); //防止raiseEvent为null,可以这样写。 raiseEvent?.Invoke(this, e); } } } //事件订阅者 public class Subscriber { private readonly string _id; public Subscriber(string id, Publisher pub) { _id = id; pub.RaiseCustomEvent += HandleCustomEvent; } void HandleCustomEvent(object sender, CustomEventArgs e) { Console.WriteLine($"{_id} received this message: {e.Message}"); } } } //自定义事件数据类 public class CustomEventArgs : EventArgs { public string Message { get; set; } public CustomEventArgs(string message) { Message = message; } } //事件是特殊类型的委托 public delegate void CustomEventHandler(object sender, CustomEventArgs args); }
示例二:接口事件与事件访问器
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp16 { class Program { static void Main(string[] args) { Shape shape = new Shape(); Subscriber1 sub1 = new Subscriber1(shape); Subscriber2 sub2 = new Subscriber2(shape); shape.Draw(); Console.WriteLine("Press any key to continue..."); Console.ReadLine(); } public interface IDrawingObject { event EventHandler OnDraw; } public interface IShape { event EventHandler OnDraw; } public class Shape : IDrawingObject, IShape { event EventHandler PreDrawEvent; event EventHandler PostDrawEvent; object objectLock = new object(); //通过提供自己的访问器,可以指定两个事件是由类中的同一个事件表示,还是由不同事件表示。 event EventHandler IDrawingObject.OnDraw { add { lock (objectLock) { PreDrawEvent += value; } } remove { lock (objectLock) { PreDrawEvent -= value; } } } event EventHandler IShape.OnDraw { add { lock (objectLock) { PostDrawEvent += value; } } remove { lock (objectLock) { PostDrawEvent -= value; } } } public void Draw() { PreDrawEvent?.Invoke(this, EventArgs.Empty); Console.WriteLine("Drawing a shape."); PostDrawEvent?.Invoke(this, EventArgs.Empty); } } //订阅者1 public class Subscriber1 { public Subscriber1(Shape shape) { IDrawingObject d = (IDrawingObject)shape; d.OnDraw += d_OnDraw; } void d_OnDraw(object sender, EventArgs e) { Console.WriteLine("Sub1 receives the IDrawingObject event."); } } //订阅者2 public class Subscriber2 { public Subscriber2(Shape shape) { IShape d = (IShape)shape; d.OnDraw += d_OnDraw; } void d_OnDraw(object sender, EventArgs e) { Console.WriteLine("Sub2 receives the IShape event."); } } } }
注意 EventArgs 类在 Microsoft.NET Framework 类库(FCL)中定义,其实现如下:
[ComVisible(true), Serializable] public class EventArgs { public static readonly EventArgs Empty = new EventArgs(); public EventArgs() { } }可以看出,该类型的实现非常简单,就是一个让其他类型继承的基类型。许多事件都没有附加信息需要传递。定义不需要传递附加数据的事件时,可直接使用 EventArgs.Empty,不用构造新的 EventArgs 对象。
示例——自定义事件类型
// 自定义新邮件事件 internal class NewMailEventArgs : EventArgs { private readonly String m_from, m_to, m_subject; public NewMailEventArgs(String from, String to, String subject) { m_from = from; m_to = to; m_subject = subject; } public String From { get { return m_from; } } public String To { get { return m_to; } } public String Subject { get { return m_subject; } } }
泛型 System.EventHandler 委托类型的定义如下:
public delegate void EventHandler<TEventArgs>(Object sender, TEventArgs e);
示例——定义事件成员
internal class MailManager { public event EventHandler<NewMailEventArgs> NewMail; protected virtual void OnNewMail(NewMailEventArgs e) {// 出于线程安全的考虑,现在将对委托字段的引用复制到一个临时变量中 EventHandler<NewMailEventArgs> temp = Volatile.Read(ref NewMail); if (temp != null) temp(this, e); }// 版本二,调用扩展方法Raise protected virtual void OnNewMail(NewMailEventArgs e) { e.Raise(this, ref NewMail); }// 当有新邮件到达时触发事件 public void SimulateNewMail(String from, String to, String subject) { NewMailEventArgs e = new NewMailEventArgs(from, to, subject); OnNewMail(e); } }
事件处理方法原型形式:
void MethodName(Object sender, NewMailEventArgs e);
事件模式要求所有事件处理方法的返回类型都是 void。遗憾的是FCL中的一些事件处理程序(比如 ResolveEventHandler)没有遵循 Microsoft 自定的模式。
public delegate Assembly ResolveEventHandler(object sender, ResolveEventArgs args);
为方便起见,可定义扩展方法来封装这个线程安全逻辑。
示例——定义扩展方法
public static class EventArgExtensions { public static void Raise<TEventArgs>(this TEventArgs e, Object sender, ref EventHandler<TEventArgs> eventDelegate) {// 出于线程安全的考虑,现在将对委托字段的引用复制到一个临时变量中 EventHandler<TEventArgs> temp = Volatile.Read(ref eventDelegate); if (temp != null) temp(this, e); } }
事件的登记和移除是线程安全的
显式实现事件
using System; using System.Collections.Generic; using System.Threading; namespace ConsoleApp25 { class Program { static void Main(string[] args) { TypeWithLotsOfEvents twle = new TypeWithLotsOfEvents(); //添加一个回调 twle.Foo += HandleFooEvent; //证明确实可行 twle.SimulateFoo(); Console.ReadLine(); } private static void HandleFooEvent(object sender, FooEventArgs e) { Console.WriteLine("Handling Foo Event here..."); } } // 这个类的目的是在使用EventSet时,提供 // 多一点的类型安全性和代码可维护性 public sealed class EventKey { } public sealed class EventSet { // 该私有字典用于维护EventKey->Delegate映射 private readonly Dictionary<EventKey, Delegate> m_events = new Dictionary<EventKey, Delegate>(); // 添加EventKey->Delegate映射(如果EventKey不存在), // 或者将委托和现有的EventKey合并 public void Add(EventKey eventKey, Delegate handler) { Monitor.Enter(m_events); Delegate d; m_events.TryGetValue(eventKey, out d); m_events[eventKey] = Delegate.Combine(d, handler); Monitor.Exit(m_events); } // 从EventKey(如果它存在)删除委托,并且 // 在删除最后一个委托时删除EventKey->Delegate映射 public void Remove(EventKey eventKey, Delegate handler) { Monitor.Enter(m_events); // 调用TryGetValue,确保在尝试从集合中删除不存在的EventKey时不会抛出异常 Delegate d; if (m_events.TryGetValue(eventKey, out d)) { d = Delegate.Remove(d, handler); //如果还有委托,就设置新的头部(地址),否则删除EventKey if (d != null) m_events[eventKey] = d; else m_events.Remove(eventKey); } Monitor.Exit(m_events); } // 为指定的EventKey引发事件 public void Raise(EventKey eventKey, Object sender, EventArgs e) { // 如果EventKey不在集合中,不抛出异常 Delegate d; Monitor.Enter(m_events); m_events.TryGetValue(eventKey, out d); Monitor.Exit(m_events); if (d != null) { // 由于字典可能包含几个不同的委托类型, // 所以无法在编译时构造一个类型安全的委托调用 // 因此,我调用System.Delegate类型的DynamicInvoke // 方法,以一个对象数组的形式向它传递回调方法的参数 // 在内部,DynamicInvoke会向调用的回调方法查证参数的 // 类型安全性,并调用方法 // 如果存在类型不匹配的情况,DynamicInvoke会抛出异常 d.DynamicInvoke(new Object[] { sender, e }); } } } // 为这个事件定义从EventArgs派生的类型 public class FooEventArgs : EventArgs { } public class TypeWithLotsOfEvents { // 定义私有实例字段来引用集合 // 集合用于管理一组“事件/委托”对 // 注意:EventSet类型不是FCL的一部分,它是自定义的类型 private readonly EventSet m_eventSet = new EventSet(); // 受保护的属性使派生类型能访问集合 protected EventSet EventSet { get { return m_eventSet; } } #region 用于支持Foo事件的代码(为附加的事件重复这个模式) // 定义Foo事件必要的成员 // 2a. 构造一个静态只读对象来标识这个事件 // 每个对象都有自己的哈希码,以便在对象的集合中查找这个事件委托链表 protected static readonly EventKey s_fooEventKey = new EventKey(); // 2b. 定义事件的访问器方法,用于在集合中增删委托 public event EventHandler<FooEventArgs> Foo { add { m_eventSet.Add(s_fooEventKey, value); } remove { m_eventSet.Remove(s_fooEventKey, value); } } // 2c. 为这个事件定义受保护的虚方法OnFoo protected virtual void OnFoo(FooEventArgs e) { m_eventSet.Raise(s_fooEventKey, this, e); } // 2d. 定义将输入转换成这个事件的方法 public void SimulateFoo() { OnFoo(new FooEventArgs()); } #endregion } }
标签: C#
« 约束执行区域(CER)
|
WPF介绍»
日历
最新文章
随机文章
热门文章
分类
存档
- 2024年11月(3)
- 2024年10月(5)
- 2024年9月(3)
- 2024年8月(3)
- 2024年7月(11)
- 2024年6月(3)
- 2024年5月(9)
- 2024年4月(10)
- 2024年3月(11)
- 2024年2月(24)
- 2024年1月(12)
- 2023年12月(3)
- 2023年11月(9)
- 2023年10月(7)
- 2023年9月(2)
- 2023年8月(7)
- 2023年7月(9)
- 2023年6月(6)
- 2023年5月(7)
- 2023年4月(11)
- 2023年3月(6)
- 2023年2月(11)
- 2023年1月(8)
- 2022年12月(2)
- 2022年11月(4)
- 2022年10月(10)
- 2022年9月(2)
- 2022年8月(13)
- 2022年7月(7)
- 2022年6月(11)
- 2022年5月(18)
- 2022年4月(29)
- 2022年3月(5)
- 2022年2月(6)
- 2022年1月(8)
- 2021年12月(5)
- 2021年11月(3)
- 2021年10月(4)
- 2021年9月(9)
- 2021年8月(14)
- 2021年7月(8)
- 2021年6月(5)
- 2021年5月(2)
- 2021年4月(3)
- 2021年3月(7)
- 2021年2月(2)
- 2021年1月(8)
- 2020年12月(7)
- 2020年11月(2)
- 2020年10月(6)
- 2020年9月(9)
- 2020年8月(10)
- 2020年7月(9)
- 2020年6月(18)
- 2020年5月(4)
- 2020年4月(25)
- 2020年3月(38)
- 2020年1月(21)
- 2019年12月(13)
- 2019年11月(29)
- 2019年10月(44)
- 2019年9月(17)
- 2019年8月(18)
- 2019年7月(25)
- 2019年6月(25)
- 2019年5月(17)
- 2019年4月(10)
- 2019年3月(36)
- 2019年2月(35)
- 2019年1月(28)
- 2018年12月(30)
- 2018年11月(22)
- 2018年10月(4)
- 2018年9月(7)
- 2018年8月(13)
- 2018年7月(13)
- 2018年6月(6)
- 2018年5月(5)
- 2018年4月(13)
- 2018年3月(5)
- 2018年2月(3)
- 2018年1月(8)
- 2017年12月(35)
- 2017年11月(17)
- 2017年10月(16)
- 2017年9月(17)
- 2017年8月(20)
- 2017年7月(34)
- 2017年6月(17)
- 2017年5月(15)
- 2017年4月(32)
- 2017年3月(8)
- 2017年2月(2)
- 2017年1月(5)
- 2016年12月(14)
- 2016年11月(26)
- 2016年10月(12)
- 2016年9月(25)
- 2016年8月(32)
- 2016年7月(14)
- 2016年6月(21)
- 2016年5月(17)
- 2016年4月(13)
- 2016年3月(8)
- 2016年2月(8)
- 2016年1月(18)
- 2015年12月(13)
- 2015年11月(15)
- 2015年10月(12)
- 2015年9月(18)
- 2015年8月(21)
- 2015年7月(35)
- 2015年6月(13)
- 2015年5月(9)
- 2015年4月(4)
- 2015年3月(5)
- 2015年2月(4)
- 2015年1月(13)
- 2014年12月(7)
- 2014年11月(5)
- 2014年10月(4)
- 2014年9月(8)
- 2014年8月(16)
- 2014年7月(26)
- 2014年6月(22)
- 2014年5月(28)
- 2014年4月(15)
友情链接
- Unity官网
- Unity圣典
- Unity在线手册
- Unity中文手册(圣典)
- Unity官方中文论坛
- Unity游戏蛮牛用户文档
- Unity下载存档
- Unity引擎源码下载
- Unity服务
- Unity Ads
- wiki.unity3d
- Visual Studio Code官网
- SenseAR开发文档
- MSDN
- C# 参考
- C# 编程指南
- .NET Framework类库
- .NET 文档
- .NET 开发
- WPF官方文档
- uLua
- xLua
- SharpZipLib
- Protobuf-net
- Protobuf.js
- OpenSSL
- OPEN CASCADE
- JSON
- MessagePack
- C在线工具
- 游戏蛮牛
- GreenVPN
- 聚合数据
- 热云
- 融云
- 腾讯云
- 腾讯开放平台
- 腾讯游戏服务
- 腾讯游戏开发者平台
- 腾讯课堂
- 微信开放平台
- 腾讯实时音视频
- 腾讯即时通信IM
- 微信公众平台技术文档
- 白鹭引擎官网
- 白鹭引擎开放平台
- 白鹭引擎开发文档
- FairyGUI编辑器
- PureMVC-TypeScript
- 讯飞开放平台
- 亲加通讯云
- Cygwin
- Mono开发者联盟
- Scut游戏服务器引擎
- KBEngine游戏服务器引擎
- Photon游戏服务器引擎
- 码云
- SharpSvn
- 腾讯bugly
- 4399原创平台
- 开源中国
- Firebase
- Firebase-Admob-Unity
- google-services-unity
- Firebase SDK for Unity
- Google-Firebase-SDK
- AppsFlyer SDK
- android-repository
- CQASO
- Facebook开发者平台
- gradle下载
- GradleBuildTool下载
- Android Developers
- Google中国开发者
- AndroidDevTools
- Android社区
- Android开发工具
- Google Play Games Services
- Google商店
- Google APIs for Android
- 金钱豹VPN
- TouchSense SDK
- MakeHuman
- Online RSA Key Converter
- Windows UWP应用
- Visual Studio For Unity
- Open CASCADE Technology
- 慕课网
- 阿里云服务器ECS
- 在线免费文字转语音系统
- AI Studio
- 网云穿
- 百度网盘开放平台
- 迅捷画图
- 菜鸟工具
- [CSDN] 程序员研修院
- 华为人脸识别
- 百度AR导航导览SDK
- 海康威视官网
- 海康开放平台
- 海康SDK下载
- git download
交流QQ群
-
Flash游戏设计: 86184192
Unity游戏设计: 171855449
游戏设计订阅号