目录
一、概述
二、事件和委托的区别
委托和事件的概念
委托和事件的作用
委托和事件的区别
三、事件的基本用法
结束
一、概述
事件是一种特殊的多播委托,仅可以从声明事件的类(或派生类)或结构(发布服务器类)中对其进行调用。 如果其他类或结构订阅该事件,则在发布服务器类引发该事件时,将调用其事件处理程序方法
可以将事件标记为public、private、protected、internal、protected internal 或 private protected。 这些访问修饰符定义该类的用户访问该事件的方式。
事件在我们平时开发中用的还是比较多的,大部分时候用在框架中,比如 Winform 中的 Timer 组件,如下面代码,Timer.Elapsed 就是一个事件
//实例化Timer类,
var Timer = new System.Timers.Timer();
//设置间隔时间(毫秒);
Timer.Interval = IntervalTime;
//到达时间的时候执行事件;
Timer.Elapsed += new System.Timers.ElapsedEventHandler(Elapsed);
//设置是执行一次(false)还是一直执行(true);
Timer.AutoReset = true;
在Visual Studio 2022 中的反编译,我们可以看到这个事件的具体写法
在我们平时所用的框架中,只要用 += 去添加方法,那基本都是事件写的。
二、事件和委托的区别
参考一些网上的资料:
委托和事件的概念
委托
C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。它本质上也是一个类。
它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法。
事件
事件由对象引发,通过我们提供的代码来处理。一个事件我们必须订阅(Subscribe)他们,订阅一个事件的含义就是提供代码,在这个事件发生时执行这些代码,这些代码称为事件处理程序。
事件是在委托类型变量前加上 event 关键字,其本质是用来对委托类型的变量进行封装,类似于类的属性对字段的封装。
委托和事件的作用
委托
可以把方法当参数传递,可以避免在程序中大量使用 if-else(switch) 语句,同时使得程序具有更好的可扩展性。C#2.0 之后出现了 匿名函数 和 lambda表达式 也是 Delegate 演化而来。
事件
事件的使用一般通过发布者和订阅者来进行。发布者会在某一条件下触发某事件,订阅者可以通过订阅该事件,来对该事件的触发做出反应。
比如,设计模式中的观察者模式.
委托和事件的区别
1、事件是委托的封装 —— 是一种特殊的委托。
2、事件里面其实就是两个方法(即 add_event() 和 remove_event())和一个私有的委托变量,这两个方法里面分别是对这个私有的委托变量进行的合并和移除,当调用事件的 += 时其实是调用的事件里面的 add_event() 方法,同样 -= 调用的是 remove_event() 方法。
3、在注册和注销事件上:
委托可以使用 = 和 += 来将函数注册到委托的变量上,使用 -= 来将函数注销。
事件则有着更严格的限制,事件只能使用 += 来将函数注册到其上,使用 -= 来将函数注销。
三、事件的基本用法
在一些比较老的项目源码中还是能看到 delegate 配合 event 这种写法的, delegate 在平时工作中使用还是比较少的,个人一般使用 Action 和 Func 委托,主要是 delegate 使用起来不是特别方便,在下面的案例中,我也会以 Action 和 Func 为主。
案例1
下面使用 delegate 配合 event 的写法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 事件demo
{
internal class Program
{
static void Main(string[] args)
{
User1 user1 = new User1();
User2 user2 = new User2();
MessageHandle.Receive("回家吃饭了");
Console.ReadKey();
}
}
public class MessageHandle
{
public delegate void OnMessage(string message);
public static OnMessage OnMessageEvent = null;
public static void Receive(string message)
{
if (OnMessageEvent != null)
OnMessageEvent(message);
}
private MessageHandle() { }
}
public class User1
{
public void Receive(string msg)
{
Console.WriteLine("User1 收到消息:" + msg);
}
public User1()
{
MessageHandle.OnMessageEvent += Receive;
}
}
public class User2
{
public void Receive(string msg)
{
Console.WriteLine("User2 收到消息:" + msg);
}
public User2()
{
MessageHandle.OnMessageEvent += Receive;
}
}
}
运行
在上面的代码中,可以直接这么写,效果一样的,我更推荐多使用 Action ,Func 的写法
public class MessageHandle
{
public static Action<string> OnMessageEvent = null;
public static void Receive(string message)
{
if (OnMessageEvent != null)
OnMessageEvent(message);
}
private MessageHandle() { }
}
案例2
在 winform 开发中,我们经常用到定时器,有时候,定时器需要一直使用,并且在很多类中使用,那么我们可以使用一个定时器,做成一个订阅机制就行了,这样可以更加方便的管理。
using System;
using System.Threading;
using System.Windows.Forms;
internal class ScanTimer
{
/// <summary>
/// 定时器回调事件
/// </summary>
public static event Action ScanEvent;
//定时器
private static System.Timers.Timer Timer = null;
//间隔时间
private static int IntervalTime = 1000;
private static void Elapsed(object source, System.Timers.ElapsedEventArgs e)
{
if (ScanEvent != null)
ScanEvent();
}
/// <summary>
/// 打开定时器
/// </summary>
public static void Start()
{
Timer.Enabled = true;
}
/// <summary>
/// 关闭定时器
/// </summary>
public static void Stop()
{
Timer.Enabled = false;
}
static ScanTimer()
{
//实例化Timer类,
Timer = new System.Timers.Timer();
//设置间隔时间(毫秒);
Timer.Interval = IntervalTime;
//到达时间的时候执行事件;
Timer.Elapsed += new System.Timers.ElapsedEventHandler(Elapsed);
//设置是执行一次(false)还是一直执行(true);
Timer.AutoReset = true;
}
private ScanTimer() { }
}
比如,上位机有些项目,需要每天固定的时间做某些事情,比如保存昨天的生产报表,我们就要写一个定时器,反复的进行判断
调用方法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 事件demo
{
internal class Program
{
static void Main(string[] args)
{
CheckTimer checkTimer = new CheckTimer();
checkTimer.Init();
ScanTimer.Start();
Console.ReadKey();
}
}
public class CheckTimer
{
public void Init()
{
ScanTimer.ScanEvent += Check;
}
public void Check()
{
if (DateTime.Now > DateTime.Parse(DateTime.Now.ToShortDateString() + " 12:00:00"))
Console.WriteLine("当前时间:" + DateTime.Now.ToString() + " 大于时间:" + DateTime.Now.ToShortDateString() + " 12:00:00");
else
Console.WriteLine("当前时间:" + DateTime.Now.ToString() + " 小于时间:" + DateTime.Now.ToShortDateString() + " 12:00:00");
}
}
}
运行:
结束
如果这个帖子对你有所帮助,欢迎 关注 + 点赞 + 留言
end