c# の 事件
1.事件的概念
事件是作为消i息的通知者,书写方便,快捷。在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。
用白话说,就是“有事”发生了,然后事件作为通知者把发生的事存储起来,然后再发给多个需要响应的观察者。
这个没做过的人,不大好理解:
打个比方:有一群贼,有毛贼、飞贼等等,而我是放哨的,所我也就是那个所谓“事件”。作为一个非常优秀的放哨的。我预先要把“有事发生”后的情况根据贼的种类进行存储成相应的黑话,例如对于飞贼我要存储–“从屋顶逃跑”,对于毛贼我要存储–“从后门溜走”之类的黑话。这时候“有事”发生了–“主人回来了”或“警察来了”,我就通知飞贼“从屋顶逃跑”,通知毛贼“从后门溜走”……
我建议楼主看一看观察者模式,事件其实就是在底层封装了那个观察者模式而已。而上面例子,放哨的就是通知者,贼就是观察者,而主人和警察就是被观察者。事件就是根据情况进行不同的响应,发出一系列不同或相同通知(消息)给作为“观察者”的类。
在以往我们编写这类程序中,往往采用等待机制,为了等待某件事情的发生,需要不断地检测某些判断变量,而引入事件编程后,大大简化了这种过程:
2.事件需要注意的地方:
- 在类里面声明。
- 发布者是一个类,订阅者是一个类。
- 可以使用
+=
和-=
添加或者删除委托。
发布者和订阅者模式:
发布者:定义了一系列其他部分可能感兴趣的事件。其他类可以 “注册” 以获取通知。
订阅者: 当事件发生时,发布者 “触发事件”,然后执行订阅者提交的所有事件。
3.例子
1.第一个事件例子
namespace VsCore_Demo {
public delegate void SaySomething (string name);
class Program {
public void SayHello (string name) {
Console.WriteLine ("Hello," + name + "!");
}
public void SayNiceToMeetYou (string name) {
Console.WriteLine ("Nice to meet you," + name + "!");
}
public event SaySomething come;
public event SaySomething come2;
public void test () {
//声明两个委托.
//声明委托的时候,传进去的参数是方法名。
SaySomething sayhello = new SaySomething (SayHello);
SaySomething saynice = new SaySomething (SayNiceToMeetYou);
//把两个委托添加到事件里
come += sayhello;
come += saynice;
//事件发生了。
//触发事件是用事件直接加参数。
come ("张三");
System.Console.WriteLine("***********");
}
static void Main (string[] args) {
Program program = new Program ();
program.test ();
Console.Read ();
}
}
}
事件声明是这样的:
public event SaySomething come;
这样表明了,come这个事件,只和SaySomething这个委托打交道。当事件发生的时候,由事件去调用这些个委托,然后由委托调用具体的实现方法。
实例化委托,注意我们用到了new关键字,就好像实例化一个类一样,然后传入一个参数,但这个参数不是string类型、也不是int类型,而是一个方法名。
SaySomething sayhello = new SaySomething (SayHello);
SaySomething saynice = new SaySomething (SayNiceToMeetYou);
我们回过头来再看一下“事件”的定义:
public event SaySomething come;
这里已经指出了“委托”的名字,所以,我们可以直接将方法加到事件上,而省略“委托”的实例化过程,因此上面的test()方法可以简单写为:
public void test()
{
come += SayHello;
come += SayNiceToMeetYou;
come("张三");
}
激发委托的时候,又回去了抽象了,直接把参数穿进去就行,中间是啥过程,他不管用。
委托+事件是观察者模式的一个典型例子,所谓的委托其实就是观察者,它会关心某种事件,一旦这种事件被触发,这个观察者就会行动
2. 事件完成:猫叫,主人醒,老鼠跑 的经典面试题
具体代码如下:
有几点需要注意:
- CatCall?.Invoke(); 唤起事件;
- 事件 += 可以翻译为 。猫叫引起了老鼠跑;
using System;
namespace DelegateDemo
{
//定义猫叫委托
public delegate void CatCallEventHandler();
public class Cat
{
//定义事件
public event CatCallEventHandler CatCall;
//定义唤醒事件的方法
public void OnCatCall()
{
Console.WriteLine("猫叫了一声");
//唤醒事件。
CatCall?.Invoke();
}
}
public class Mouse
{
//定义老鼠跑掉方法
public void MouseRun()
{
Console.WriteLine("老鼠跑了");
}
}
public class People
{
//定义主人醒来方法
public void WakeUp()
{
Console.WriteLine("主人醒了");
}
}
class Program
{
static void Main(string[] args)
{
Cat cat = new Cat();
Mouse m = new Mouse();
People p = new People();
//关联绑定
cat.CatCall += new CatCallEventHandler(m.MouseRun);
cat.CatCall += new CatCallEventHandler(p.WakeUp);
cat.OnCatCall();
Console.ReadKey();
}
}
}
3.苹果降价的代码:
使用的是事件的标准形式
class Program
{
static void Main(string[] args)
{
Apple ap1 = new Apple()
{
Preice = 5288
};
//注册事件
// 点了 += 以后,可以使用快捷键生成。
ap1.myEvent += PriceChanged;
//调整价格,触发事件
ap1.Preice = 3999;
Console.ReadKey();
}
//事件响应程序
static void PriceChanged(object sender, MyEventArgs e)
{
Console.WriteLine("年终大促销,iPhone 6 只卖 " + e.NewPrice +" 元, 原价 " + e.OldPrice + " 元,快来抢!"+sender.ToString());
}
}
/// <summary>
/// 事件参数类
/// </summary>
public class MyEventArgs : EventArgs
{
public MyEventArgs(decimal newPrice, decimal oldPrice)
{
this.NewPrice = newPrice;
this.OldPrice = oldPrice;
}
public readonly decimal NewPrice;
public readonly decimal OldPrice;
}
/// <summary>
/// 事件发布者类
/// </summary>
public class Apple
{
private decimal price;
public decimal Preice
{
get
{
return price;
}
set
{
//如果价格变了,触发事件通知用户价格变了
if (price == value)
{
return;
}
decimal oldPrice = price;
price = value;
//调用触发事件的方法。
//一般激活方法是 On + event
OnRaiseEvet(new MyEventArgs(price, oldPrice));
}
}
public event EventHandler<MyEventArgs> myEvent;
//激发方法。
public virtual void OnRaiseEvet(MyEventArgs e)
{
//如果调用列表不为空,则触发
if (myEvent != null)
{
myEvent(this, e);
//event关键字定义的事件只能由事件源对象自己激发,外界无法通过访问委托变量直接激发事件。
//下面的代码无法编译通过:Publisher p = new Publisher(); p.MyEvent(10);
}
}
}
关于事件
- 事件的主要目的是防止订阅者之间相互干扰。
- 声明事件,直接在委托前边加 event
- 内外有别: 事件在类里面的时候,可以当委托一样用,而在类外边,只能进行+= 和 – = 的操作
- 一般情况下,激活事件的方法,都默认用 On+事件 命名
- 激活使用 CatCall?.Invoke()
- 使用
event
来作为关键字,有什么强制规定?(1)只能在包容类,才能发送向订阅者发出的委托,(2)类外边不允许使用 =。 - sender 是用来输出发布者类的。
- 对于事件来说,外部只能注册自己+=,注销自己-=,外界不可以注销其他的注册者,