標籤:本質 ons 其他 ati and ack key att generic
今天來說一下C#的事件,說起事件不得不提委託,回呼函數。其實這三者最本質的方面就是委託(函數指標)的運用,委託只是最基礎的部分,定義了一個可以指向其他方法(函數) 的對象(簡單理解就是一個指標變數)。其實很多文章都談到委託,回呼函數和事件,但是都講的很籠統,大神的理解固然深刻,但是對於初學者不易理解。委託的理解可以如上述所說,而回呼函數則可以理解為一個方法在運行時調用了另一個方法,即它的入口參數中需要另外一個方法。
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace CallBack{ /// <summary> /// 通過sayhello方法調用hello方法,看似多次一舉,其實代表了一種思路,即 /// 把方法的行為與行為主體(本例中為name)分開 /// </summary> /// <param name="h"></param> public delegate void newDelegate(string h); class Program { static void Main(string[] args) { SayHello("Andy", Hello); Console.ReadKey(); } //調用函數 static void SayHello(string name,newDelegate Hello) { Hello(name); } //回呼函數 static void Hello(string name) { Console.WriteLine(name + "你好!"); } }}
回呼函數與事件是以委託為基礎的,事件與回呼函數在本質上都屬於委託的應用,所以在本質上兩者並沒有太大界限,在很多解釋回呼函數的例子中,由於寫的比較複雜,其實已經屬於事件機制。所謂事件其實也是一個方法調用另一個方法。對事件進行細分流程可以這樣理解:
1、首先要發布事件
public delegate void reactEventhander();//定義一個委託 //此處event可以不加,程式依舊可以運行,只是在類外部可以對事件進行修改,增加event可以避免 public event reactEventhander RegularReact;//發布兩個事件 public event Eventhander MagicReact;
2、定義事件觸發的條件(也可以無條件觸發)
//定義事件觸發的條件 //攻擊者發動普通攻擊時,被攻擊者的反應 public void RegularAttack() { Console.WriteLine("發起了普通攻擊!"); if(RegularReact!=null)//判斷事件是否被訂閱 { RegularReact(); } } public void MagciAttack() { Console.WriteLine("發起了魔法攻擊!"); if (RegularReact != null)//判斷事件是否被訂閱 { MagicReact(); } }
3、事件被訂閱
public Enemy1(Attacker a) { //Enemy1對事件進行了訂閱,遭受攻擊時反應 a.RegularReact += new reactEventhander(a_RegularAttacek); a.MagicReact += new reactEventhander(a_MagciAttacek); }
4、最後事件發生
通過下邊例子說明。此例子來類比兩個小怪(enemy1、enemy2)同時遭受attacker時的受傷害情況(enemy2由於層級較低,掉血較多)
/// <summary> /// 類比兩個小怪(enemy1、enemy2)同時遭受attacker時的受傷害情況 /// enemy2由於層級較低,掉血較多 /// attacker 可以進行普通攻擊和魔法攻擊,同時發布兩種攻擊發起時,遭受者的反應 /// enemy1、enemy2對遭受兩種攻擊時的反應進行了訂閱 /// </summary> public delegate void reactEventhander();//定義一個委託 class Attacker { public event reactEventhander RegularReact;//發布兩個事件 public event reactEventhander MagicReact; //定義事件觸發的條件 //攻擊者發動普通攻擊時,被攻擊者的反應 public void RegularAttack() { Console.WriteLine("發起了普通攻擊!"); if(RegularReact!=null)//判斷事件是否被訂閱 { RegularReact(); } } public void MagciAttack() { Console.WriteLine("發起了魔法攻擊!"); if (RegularReact != null)//判斷事件是否被訂閱 { MagicReact(); } } } class Enemy1 { public Enemy1(Attacker a) { //Enemy1對事件進行了訂閱,遭受攻擊時反應 a.RegularReact += new reactEventhander(a_RegularAttacek); a.MagicReact += new reactEventhander(a_MagciAttacek); } //受到普通攻擊時的反應 public void a_RegularAttacek() { Console.WriteLine("Enemy1遭受普通攻擊,掉血100!"); } //受到魔法攻擊時的反應 public void a_MagciAttacek() { Console.WriteLine("Enemy1遭受魔法攻擊,掉血100!"); } } class Enemy2 { public Enemy2(Attacker a) { //Enemy1對事件進行了訂閱,遭受攻擊時反應 a.RegularReact += new reactEventhander(a_RegularAttacek); a.MagicReact += new reactEventhander(a_MagciAttacek); } //受到普通攻擊時的反應 public void a_RegularAttacek() { Console.WriteLine("Enemy2遭受普通攻擊,掉血300!"); } //受到魔法攻擊時的反應 public void a_MagciAttacek() { Console.WriteLine("Enemy2遭受魔法攻擊,掉血300!"); } } class Program { static void Main(string[] args) { Attacker att = new Attacker(); Enemy1 e1 = new Enemy1(att); Enemy2 e2 = new Enemy2(att); att.RegularAttack(); att.MagciAttack(); Console.ReadKey(); } }
仔細會看此例子,剝去所有的亂七八糟的,也不過是attacker的regularattack和magicattack方法調用了enemy1/2的a_RegularAttacek和a_MagciAttacek方法,只不過是通過attacker發布的兩個事件進行訂閱的。從此小例子上來講,為了協助理解,此處完全可以去掉兩個event,在兩個enemy的a_RegularAttacek和a_MagciAttacek方法中加入委託類型的入口參數。但是事件的這種機制思想確實很重要的,以後會慢慢體會到的。
C#事件