天天看點

C#中的委托與事件執行個體詳解

本人部落格中的代碼都是本地測試通過,意思和注釋了解了就行

本篇文章引用張子陽部落格基本思路,然後根據自己的經驗,進行了部分的簡化和修改,委托就在于了解,多看幾遍就了解了。

委托:本質上講委托是一種可以将方法作為參數的方法,可以包含參數也可以不包含參數

事件:從本質上将也是委托,隻不過是進行了封裝的委托。事件可以綁定方法,綁定之後就會監視這些方法,當達到事件的觸發條件,就會執行事件綁定的方法

如果比較繞口的話請讀10遍就了解了

分五個步驟:

1.委托将方法作為參數傳遞:将方法作為參數進行傳遞,當某一個方法作為參數傳遞時,一起傳遞的還有這個方法對應的參數

舉例:

class Program
{
    //定義委托
    public delegate void GreetDelegate();
    private static void EnglishGreeting(string name)
    {
        Console.WriteLine("Morning,"+name);
    }
    private static void ChaineseGreeting(string name)
    {
        Console.WriteLine("早上好,"+name);
    }
    //定義一個接收GreetingDelegate類型的方法
    private static void GreetPeople(string name,GreetDelegate MakeGreeting)
    {
        MakeGreeting(name);
    }
    
    static void Main(string[] args)
    {
        //将方法作為參數傳遞,并同時傳遞方法執行需要的參數
        GreetPeople("cdc",EnglishGreeting);
        GreetPeople("奇點碼農",ChineseGreeting);
        Console.ReadKey();
    }
}
           

2.委托可以通過+=綁定方法,也可以通過-=消除委托對方法的綁定

//将方法綁定到委托
class Program
{
    public delegate void GreetDelegateHandler(string name);
    public static void EnglishGreeting(string name)
    {
        Console.WriteLine("Morning,"+name);
    }
    private static void ChineseGreeting(string name)
    {
        Console.WriteLine("早上好,"+name);
    }

    static void Main(string[] args)
    {
        GreetDelegateHandler delegate1;
        //将方法綁定到委托
        delegate1=EnglishGreeting;
        delegate1+=ChineseGreeting;
        delegate1("cdc");
    }
}
           

3.事件出馬:事件類似于進行了封裝的委托類型的變量,事件的參數與與之對應的委托的參數一緻

class Program
{
    public delegate void GreetDelegateHandler(string name);
    
    private static void EnglishGreeting(string name)
    {
        Console.WriteLine("Morning,"+name);
    }

    private static void ChineseGreeting(string name)
    {
        Console.WriteLine("早上好,"+name);
    }
    
    public class GreetManager
    {
        public event GreetDelegateHandler GreetDelegate;
        
        public void GreetPeople(string name)
        {
            //事件的參數與與之對應的委托的參數一緻
            GreetDelegate(name);
        }
    }

    static void Main(string[] args)
    {
        GreetManager gm=new GreetManager();    
        gm.GreetDelegate+=EnglishGreeting;
        gm.GreetDelegate+=ChineseGreeting;
        gm.GreetPeople("cdc");
        Console.ReadKey();
    }
}
           

4.Observer設計模式

(1)Subject:被監視對象,包含着其他對象感興趣的内容

(2)Observer:監視者,監視Subject,當Subject中的某事件發生的時候,會告知Observer,而Observer則會采取相應行動

//注:Observer設計模式是為了定義對象的一種一對多的依賴關系,以便當一個對象的狀态改變時,其他依賴于它的對象會自動告知并更新執行

//被監視對象
public class Heater
{
    private int temperature;
    //聲明委托
    public delegate void BoilHandler(int param);
    //使用委托聲明事件
    public event BoilHandler BoilEvent;
    //燒水
    public void BoilWater()
    {
        for(int i=0;i<=100;i++)
        {
            Thread.Sleep(500);
            temperature=i;
            if(temperature>95)
            {
                if(BoilEvent!=null)
                {
                    BoilEvent(temperature);
                }
            }
        }
    }
}
//監視者:警報器
public class Alarm
{
    public void MakeAlert(int param)
    {
        Console.WriteLine("Alarm:滴滴。。。,水已經{0}度了",param);
    }
}
//監視者:顯示器
public class Display
{
    public static void ShowMsg(int param)
    {
        Console.WriteLine("Display:水快燒開了,目前溫度:{0}度",param);
    }
}

class Program
{
    static void Main(string[] args)
    {
        Heater heater=new Heater();
        Alarm alarm=new Alarm();
        //注冊方法
        heater.BoilEvent+=alarm.MakeAlert;
        //給匿名對象注冊方法
        heater.BoilEvent+=(new Alarm()).MakeAlert;
        //注冊靜态方法
        heater.BoilEvent+=Display.ShowMsg;
        //調用被監視對象執行方法,每當被監視對象的方法中觸發一次事件,就會将該事件綁定的所有監視者方法執行一遍
        heater.BoilWater();
        Console.ReadKey();
    }
}
           

5.委托類型的代碼規範

(1)委托類型的名稱都應該以Event Handler結束

(2)委托的原型定義有一個void傳回值,并接收兩個輸入參數:一個Object類型,一個EventArgs類型(或者繼承自EventArgs)

(3)事件的命名為委托去掉EventHandler之後的剩餘部分

(4)繼承自EventArgs的類型應該以EventArgs結尾

//熱水器
public class Heater
{
    private int temperature;
    //添加型号作為示範
    public string type="RealFire001";
    //添加産地作為示範
    public string area="China Xian";
    //聲明委托
    public delegate void BoiledEventHandler(object sender,BoiledEventArgs e);
    //聲明事件
    public event BoiledEventHandler Boiled;
    //定義BoiledEventArgs類,傳遞給Observer所感興趣的資訊
    public class BoiledEventArgs:EventArgs
    {
        public readonly int temperature;
        public BoiledEventArgs(int temperature)
        {
            this.temperature=temperature;
        }
    }
    
    //可以供繼承自Heater類的重寫,以便繼承類拒絕其他對象對它的監視
    protected virtual void OnBoiled(BoiledEventArgs e)
    {
        //如果該事件已經注冊方法,則觸發對應的方法
        if(Boiled!=null)
        {
            //調用所有注冊對象的方法
            Boiled(this,e);
        }
    }
    //燒水
    public void BoilWater()
    {
        for(int i=90;i<=100;i++)
        {
            Thread.Sleep(500);
            temperature=i;
            if(temperature>95)
            {
                //建立Boiled的EventArgs對象
                BoiledEventArgs e=new BoiledEventArgs(temperature);
                OnBoiled(e);
            }
        }   
    }
}

//螢幕:警報器
public class Alarm
{
    public void MakeAlert(object sender,Heater.BoiledEventArgs e)
    {
        Heater heater=(Heater)sender;
        //通路sender中的公共字段
        Console.WriteLine("Alarm:{0}-{1}:",heater.area,heater.type);
        Console.WriteLine("Alarm:滴滴,水溫{0}度!",e.temperature);
        Console.WriteLine();
    }
}
//螢幕:顯示器
public class Display
{
    public static void ShowMsg(object sender,Heater.BoiledEventArgs e)
    {
        Heater heater=(Heater)sender;
        Console.WriteLine("Display:{0}-{1}:",heater.area,heater.type);
        Console.WriteLine("Display:顯示水溫{0}度。",e.temperature);
        Console.WriteLine();
    }
}

class Program
{
    static void Main(string[] args)
    {
        Heater heater=new Heater();
        Alarm alarm=new Alarm();
        //注冊方法
        heater.Boiled+=alarm.MakeAlert;
        //給匿名對象注冊方法
        heater.Boiled+=(new Alarm()).MakeAlert;
        //注冊方法
        heater.Boiled+=new Heater.BoiledEventHandler(alarm.MakeAlert);
        //注冊靜态方法
        heater.Boiled+=Display.ShowMsg;
        //調用燒水的方法,會自動調用注冊的方法
        heater.BoilWater();
        Console.ReadKey();
    }
}