事件
作者:追风剑情 发布于: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介绍»
日历
最新文章
随机文章
热门文章
分类
存档
- 2025年11月(1)
- 2025年9月(3)
- 2025年7月(4)
- 2025年6月(5)
- 2025年5月(1)
- 2025年4月(5)
- 2025年3月(4)
- 2025年2月(3)
- 2025年1月(1)
- 2024年12月(5)
- 2024年11月(5)
- 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
- Open CASCADE
- CascadeStudio
交流QQ群
-
Flash游戏设计: 86184192
Unity游戏设计: 171855449
游戏设计订阅号









