从拳皇97中浅谈C#委托与事件
2021-02-12 22:18
先看看下列代码:
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnSearch_Click(object sender, ImageClickEventArgs e)
{
}
是不是很眼熟呢?其中的参数(sender,e)到底是代表的是什么呢?这就要涉及到C#的委托与事件。
那我们首先来看一下比较正统的感念吧:
事件是类在发生其关注的事情时用来提供通知的一种方式。
事件的发生一般都牵扯2个角色
事件发行者(Publisher):一个事件的发行者,也称作是发送者(参数:sender),其实就是个对象,这个对象会自行维护本身的状态信息(参数:e),当本身状态信息变动时,便触发一个事件,并通知说有的事件订阅者。
事件订阅者(Subscriber):对事件感兴趣的对象,也称为Receiver,可以注册感兴趣的事件,在事件发行者触发一个事件后,会自动执行这段代码。
委托就好比:现实生活中的中介机构,比如我们通过租房的中介,我们把租房的需求告诉给他们,然后他们去帮我们去找住所。我们只需要关心自己的能够承担多少的价格或者环境什么之类的,并不参与找房子这个过程.
事件就好比:很多人都去找租房的中介去租房子,根据不同的需求找到了不同的住所,然后同时通知所有的人,让他们去看房子。比如说 张三 李四 王二麻子,他们三兄弟,其中 张三和李四对住房的条件不是很挑剔,王二麻子就很日怪,他就喜欢潮湿一点的房子, 然后他们一起找到了中介公司(发送委托),中介公司了解到了他们的需求,全部都记录在自己的笔记本上(添加事件),以便对自己的房源进行筛选(过滤),最后中介公司分别通知他们去看房子(执行事件)。
所以从本质上来说 : 事件 等价于 委托链
比如拳皇97中,当我们在控制一个角色的时候,输入不同的有效键位,会出来不同的动作。每一个角色都有自己的技能(类似上面的租房需求),但是什么时候触发这个技能(交给委托,角色自己不关心),就是在我们正确的按键了过后,才能够执行(完成委托).
下面从一个简单的demo中来理解这个概念:(有两个角色 :八神庵,草稚京)
先定义一个类SkillEventArgs ,用来保存用户输入的状态信息。
///所有订阅者【Subscriber】,也就是e,都要继承微软的EventArgs(这是一种。net的规范) //本例中订阅者【也称观察者】八神庵,草稚京 他们感兴趣的e对象,就是【action】 ,也就是我们输入的键位保存在这里 class SkillEventArgs : EventArgs { public string Action { get; set; } public SkillEventArgs(string action) { this.Action = action; } }
接着定义一个类Publish,作为中介机构.
// 发布者【Publisher】 class Publisher { public delegate void InputKeyboardEventHandler(object sender, SkillEventArgs e); // 定义委托,只处理 观察者感兴趣的e对象,所以作为参数传入. sender 也就是监视对象,本例中就是Publisher public event InputKeyboardEventHandler InputKeyboardEvent; // 定义事件,保存所有的委托链. protected virtual void OnInputKeyboard(SkillEventArgs e) // 事件只能在方法里触发,这里是触发对应角色的技能输出。 { if (InputKeyboardEvent != null) { //Sender = this,也就是Publisher InputKeyboardEvent(this,e); } //InputKeyboardEvent?.Invoke(this, e); 等价于 上面的代码 } public void UseSkill(string skill) // 实列对外的函数调用。 { SkillEventArgs skills = new SkillEventArgs(skill); OnInputKeyboard(skills); } }
定义一个抽象类 Person类: 其中有一个字典类型的Skills属性,保存的是触发的组合键,以及对应的技能名称. 还有一个是 UseSkill的抽象方法. 以及继承Person类的 八神类 和 草稚京类
abstract class Person { public static Dictionarystring, string> Skills { get; set; } public abstract void UseSkill(object sender, SkillEventArgs e); } class Iori : Person { static Iori() { Skills = new Dictionarystring, string>(); Skills.Add("k", "百式·鬼燃烧"); } public override void UseSkill(object sender, SkillEventArgs e) { if (Skills.ContainsKey(e.Action)) { Console.WriteLine(Skills[e.Action]); } else { Console.WriteLine("我 八神庵 没有此技能!!"); } } } class Kyo : Person { static Kyo() { Skills = new Dictionarystring, string>(); Skills.Add("k", "里百八式·大蛇雉"); } public override void UseSkill(object sender, SkillEventArgs e) { if (Skills.ContainsKey(e.Action)) { Console.WriteLine(Skills[e.Action]); } else { Console.WriteLine("我 草稚京 没有此技能!!"); } } }
最后在Main函数上输出:
static void Main(string[] args) { while (true) { Console.WriteLine("选择你要控制的角色:"); Console.WriteLine("a:八神庵"); Console.WriteLine("b:草稚京"); string role = Console.ReadLine(); if (role == "a") { Console.WriteLine("正在使用八神庵"); } else if (role == "b") { Console.WriteLine("正在使用草稚京"); } else { Console.WriteLine("没有此角色"); continue; }; while (true) { Console.WriteLine("请出招:"); string skill = Console.ReadLine(); Publisher p = new Publisher(); if (role == "a") { p.InputKeyboardEvent += new Iori().UseSkill; //绑定事件 } else { p.InputKeyboardEvent += new Kyo().UseSkill; } p.UseSkill(skill); } } }
效果: