委托是具有相同签名的函数(方法)的类型,事件是委托的应用方式之一。
委托相当于一个对方法的引用,可以将方法当做参数来传递,而事件相当于特殊的委托。
声明事件(Event)
在类的内部声明事件,首先必须声明该事件的委托类型。例如:
public delegate void MyDelegateHandler();
然后,声明事件本身,使用 event 关键字:
// 基于上面的委托定义事件
public event MyDelegateHandler MyDelegate;
区别/event的作用
[infobox title=”1.封装发布”]delegate可以在任何地方Invoke,event只能在类内Invoke,是为了明确事件发送对象是谁;[/infobox] [infobox title=”2.封装订阅”]delegate除了使用+=或-=来监听和移除方法,还可以用=,这样子使用会不小心把监听列表都覆盖掉;而event规范化了只能用+=和-=,或者在包含类内使用=;
高级用法/C#中对事件是如何处理
C#中的事件处理实际上是一种具有特殊签名的delegate,象下面这个样子:
public delegate void MyEventHandler(object sender, MyEventArgs e);
其中的两个参数,sender代表事件发送者,e是事件参数类。MyEventArgs类用来包含与事件相关的数据,所有的事件参数类都必须从System.EventArgs类派生。当然,如果你的事件不含参数,那么可以直接用System.EventArgs类作为参数。
就是这么简单,结合delegate的实现,我们可以将自定义事件的实现归结为以下几步:
1.定义delegate对象类型,它有两个参数,第一个参数是事件发送者对象,第二个参数是事件参数类对象。
2.定义事件参数类,此类应当从System.EventArgs类派生。如果事件不带参数,这一步可以省略。
3.定义”事件处理方法,它应当与delegate对象具有相同的参数和返回值类型”。
4.用event关键字定义事件对象,它同时也是一个delegate对象。
5.用+=操作符添加事件到事件队列中(-=操作符能够将事件从队列中删除)。
6.在需要触发事件的地方用调用delegate的方式写事件触发方法。一般来说,此方法应为protected访问限制,既不能以public方式调用,但可以被子类继承。名字是OnEventName。
7. 在适当的地方调用事件触发方法触发事件。
例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 事件
{
class EventTest
{
// 步骤1,定义delegate对象
private delegate void EventHandler<TEventArgs>(object sender, TEventArgs e)
where TEventArgs : EventArgs;
// 步骤4,用event关键字定义事件对象
private EventHandler myEvent;
// 步骤2(定义事件参数类)
public class TestEventArgs : EventArgs
{
public string args1 = "这是参数1";
public string args2 = "这是参数2";
}
public EventTest()
{
// 步骤5,用+=操作符将事件添加到队列中
myEvent += HandleFunc;
}
// 步骤3,定义事件处理方法,它与delegate对象具有相同的参数和返回值类型
public void HandleFunc(object sender, EventArgs e)
{
Console.WriteLine("调用者:" + sender.ToString());
TestEventArgs testEventArgs = e as TestEventArgs;
Console.WriteLine(testEventArgs.args1);
Console.WriteLine(testEventArgs.args2);
}
public void InvokeTest()
{
// 步骤6,触发事件
myEvent(this, new TestEventArgs());
}
}
class Program
{
static void Main(string[] args)
{
EventTest eventTest = new EventTest();
eventTest.InvokeTest();
}
}
}
再来一个栗子:
主人养了一条忠实的看门狗,晚上主人睡觉的时候,狗负责看守房子。一旦有小偷进来,狗就发出一个Alarm事件,主人接到Alarm事件后就会采取相应的行动。
//事件发送者
class Dog
{
//1.声明关于事件的委托;
public delegate void AlarmEventHandler(object sender, EventArgs e);
//2.声明事件;
public event AlarmEventHandler Alarm;
//3.编写引发事件的函数;
public void OnAlarm()
{
if (this.Alarm != null)
{
Console.WriteLine("/n狗报警: 有小偷进来了,汪汪~~~~~~~");
this.Alarm(this, new EventArgs()); //发出警报
}
}
}
//事件接收者
class Host
{
//4.编写事件处理程序
void HostHandleAlarm(object sender, EventArgs e)
{
Console.WriteLine("主 人: 抓住了小偷!");
}
//5.注册事件处理程序
public Host(Dog dog)
{
dog.Alarm += new Dog.AlarmEventHandler(HostHandleAlarm);
}
}
//6.现在来触发事件
class Program
{
static void Main(string[] args)
{
Dog dog = new Dog();
Host host = new Host(dog);
//当前时间,从2008年12月31日23:59:50开始计时
DateTime now = new DateTime(2008, 12, 31, 23, 59, 50);
DateTime midnight = new DateTime(2009, 1, 1, 0, 0, 0);
//等待午夜的到来
Console.WriteLine("时间一秒一秒地流逝... ");
while (now < midnight)
{
Console.WriteLine("当前时间: " + now);
System.Threading.Thread.Sleep(1000); //程序暂停一秒
now = now.AddSeconds(1); //时间增加一秒
}
//午夜零点小偷到达,看门狗引发Alarm事件
Console.WriteLine("/n月黑风高的午夜: " + now);
Console.WriteLine("小偷悄悄地摸进了主人的屋内... ");
dog.OnAlarm();
}
}
当午夜时分小偷到达时,dog调用dog.OnAlarm()函数,从而触发Alarm事件,于是”系统”找到并执行了注册在Alarm事件中的事件处理程序HostHandleAlarm()。
事件处理委托习惯上以EventHandler结尾,比如AlarmEventHandler。事件Alarm实际上是事件处理委托AlarmEventHandler的一个实例。引发事件的代码常常被编写成一个函数,.NET约定这种函数的名称为“OnEventName”,比如OnAlarm()的函数。在Host类中,我们定义了事件处理程序HostHandleAlarm(),并把它注册到dog.Alarm事件中。
事件处理程序的参数应该和事件委托相同。一般情况下,事件处理程序接受两个参数,一个是事件的发送者sender,一个是事件参数e。事件参数用于在发送者和接收者之间传递信息。
最近通过练习多少发现了些和大角虫差距的地方,
举个栗子,
根据传递进来参数的不同来选择不同的处理方式
像我这种鶸可能首先想到的就是if-else
而dalao可能会选用委托的方式
咋一看虽然用if-else也能解决问题
但是差距就体现在这
dalao的做法效率会更高
自己一看,
原来如此,斯国一~
自己想不到用更高级的方法去解决问题
这才是自己需要进步的地方
_(:з」∠)_