1. 程式人生 > >從拳皇97中淺談C#委托與事件

從拳皇97中淺談C#委托與事件

n) virtual 所有 [] 輸出 rri strac 理解 簡單

先看看下列代碼:

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 Dictionary<string, string> Skills { get; set; }
        public abstract void UseSkill(object sender, SkillEventArgs e);
    }

class Iori : Person
    {
        static Iori()
        {
            Skills = new Dictionary<string, 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 Dictionary<string, 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);
                }
            }
        }

效果:

技術分享圖片

從拳皇97中淺談C#委托與事件