C#學習筆記9

來源:互聯網
上載者:User

標籤:多播委託   ica   方法   沒有   使用   send   學習筆記   答案   執行   

1.多播委託:由與delegate關鍵字聲明的委託,在編譯後預設繼承Delegate與MulticastDelegate類型,所以聲明的委託自然就含有多播委託的特性,即一個委託變數可以調用一個方法鏈(多個相同簽名的方法)。在C#中,多播委託的實現是一個通用的模式,目的是避免大量的手工編碼,這個模式稱為Observer(觀察者)或者publish-subscribe(發布-訂閱)它要應對的就這樣一種情形,你需要將單一事件的通知(比如對象狀態發生了一個變化)廣播給多個訂閱者。

2.將“-=”運算子應用於委託會返回一個新執行個體:既然委託是一個參考型別,那麼肯定會有人覺得奇怪,為什麼賦值給一個局部變數,再用那個局部變數就可以保證Null檢查的執行緒安全性?由於localOnChange指向的位置就是OnTemperatureChange指向的位置,所以很自然的一個結論就是:OnTemperatureChange中發生的任何改變都會在localOnChange中反映出來。但實情真是這樣的嗎?

  答案是否定的,因為事實上對OnTemperatureChange -= <listener> 的任何調用都不會從OnTemperatureChange刪除一個委託而使它的委託比之前少一個。相反,會將一個全新的多播委託指派給它,這不會對原始的多播委託產生任何影響(localOnChange也指向那個原始的多播委託)。可查看Thermostat類中的代碼。

3.委託運算子:“+=”與“-=”的操作,代表添加與移除一個委託方法,使用“=”賦值運算子會清除所有的訂閱者,當然使用“+”與“-”操作效果是一樣的。當然無論“+= -= + -”這些操作符,在內部都是使用靜態方法Delegate.Combine()和Delegate.Remove()來實現的。Combine()方法支援兩個參數都為null。

4.委託的順序調用:在一個委託變數中含有多個委託方法(訂閱者),其執行一次委託變數(發布),不是同時執行期內含有的多個委託方法,而是順序執行含有的委託方法,通常是按照添加時的順序執行委託鏈中的方法,但這個順序有可能被覆蓋,所以程式員不應依賴於一個特定的調用順序。

5.多播委託的內部機制:前面已經說明delegate關鍵字的聲明委託,會繼承Delegate與MulticastDelegate類型,也就是說delegate關鍵字是派生自MulticastDelegate的一個類型的別名。MulticastDelegate類除了包含一個對象引用(Target)和方法指標(Method),這和它的Delegate基類是一樣的,除此之外還包含對另一個MulticastDelegate對象的引用。向一個多播委託添加一個方法時,MulticastDelegate類會建立一個委託類型的新執行個體,在新執行個體中為新增的方法儲存物件引用與方法指標,並在委託執行個體列表中添加新的委託執行個體作為下一項,這樣的結果就是,MulticastDelegate類維護著由多個Delegate對象構成的一個鏈表(可以理解為多播委託內部有一個類似集合功能來管理多個委託方法)。

6.多播委託的錯誤處理:錯誤處理凸顯了順序通知的重要性,假如一個訂閱者引發了一個異常,鏈中的後續訂閱者就接收不到通知。為了避免這個問題,使所有的訂閱者都收到通知,必須手動遍曆訂閱者列表,並單獨調用它們,把它們放到try-catch塊中。可查看Thermostat類中的代碼。

7.方法傳回值與參數引用:在多播委託中若要獲得每一個訂閱者的傳回值,需要手工遍曆委託連結收傳回值,否則直接調用委託鏈會返回最後一個委託方法的傳回值,同理ref、out修飾的參數也是一樣的。

8.事件與委託的區別:在Thermostat類中,可以不使用event關鍵字修飾委託變數,直接使用委託變數處理也能完成相應的工作,但是直接使用委託,存在2個隱患,分別為“使用賦值運算子覆蓋了以前的委託方法,可以在聲明類的外部執行發布”,使用了event就可以對委託進行封裝(由編譯器產生封裝的代碼)。相應的2個隱患就消除了,其只能在聲明類中執行發布,只能對委託進行註冊與消除(不能覆蓋,清空)。

9.EventHandler<TEventArgs>委託是.net2.0添加的泛型委派,內中包含object類型觸發源,事件標記參數(可繼承擴充其他資料),在任何類中使用sender-EventArgs模式,都不必聲明它自己的委託定義,可以直接使用EventHandle泛型委派。

10.事件的內部機制:C#編譯器會擷取帶有event修飾符的public委託變數,並將委託聲明private,除此之外,它還添加了2個方法和2個特殊的事件塊。從本質上說,event關鍵字是編譯器用於產生恰當封裝邏輯的一個C#捷徑。可查看Thermostat2類的代碼。

11.自訂事件的實現:編譯器為“+=”與“-=”產生的程式碼是可以自訂的,例如,假定改變OnTemperatureChange委託的範圍,使它成為protected而不是private,這樣就可以從衍生類別進行訪問,而無需受到和外部類一樣的限制,為此C#允許添加訂製的add和remove塊,為事件封裝的各個組成部分添加自己的實現。可查看Thermostat3類的代碼。

public class Thermostat{    private float currentTemperature;    public float CurrentTemperature    {        get { return currentTemperature; }        set        {            if (currentTemperature != value)            {                currentTemperature = value;                /* 1.在這裡並沒有一開始就檢查空值,而是首先將OnTemperatureChange賦值給另一個委託變數localOnChange,這個簡單的修改可以確保在檢查空值與發送通知之間,假如                 * 所有的OnTemperatureChange訂閱者都被移除(由一個不同的線程),那麼不會觸發NullReferenceException異常。                 * 2.                */                var localOnChange = OnTemperatureChange;                if (localOnChange == null)                {                    return;                }                //此處的遍曆與錯誤處理,是防止在多播委託執行時,若在委託鏈中有一個委託方法出現錯誤,後續的委託方法執行就會中斷。                foreach (EventHandler<TemperatureArgs> item in localOnChange.GetInvocationList())                {                    try                    {                        item(this, new TemperatureArgs(value));                    }                    catch (Exception ex)                    {                        Console.WriteLine(ex.Message);                    }                }            }        }    }    //OnTemperatureChange = delegate { };賦值一個空委託,代表零個偵聽者構成的集合,就可以引發偵聽而不必檢查是否有任何偵聽者。    public event EventHandler<TemperatureArgs> OnTemperatureChange;    /// <summary>    /// 觀察者模式樣本    /// </summary>    public static void Observer()    {        Adjust heater = new Adjust("heater", 50f, (original, newValue) => original > newValue);        Adjust cooler = new Adjust("cooler", 70f, (original, newValue) => original < newValue);        Thermostat thermostat = new Thermostat();        thermostat.OnTemperatureChange += heater.OnTemperatureChange;        thermostat.OnTemperatureChange += (sender, eArgs) => { throw new ApplicationException(); };        thermostat.OnTemperatureChange += cooler.OnTemperatureChange;        thermostat.CurrentTemperature = 40f;        thermostat.OnTemperatureChange(null, null);    }}public class TemperatureArgs : EventArgs{    public TemperatureArgs(float newTemprature)    {        NewTemprature = newTemprature;    }    public float NewTemprature { get; set; }}//C#編譯器一旦遇到event關鍵字,就會產生與Thermostat2類中代碼的等價代碼的CIL代碼。public class Thermostat2{    /*private EventHandler<TemperatureArgs> onTemperatureChange;    public void add_OnTemperatureChange(EventHandler<TemperatureArgs> handler)    {        Delegate.Combine(onTemperatureChange, handler);    }    public void remove_OnTemperatureChange(EventHandler<TemperatureArgs> handler)    {        Delegate.Remove(onTemperatureChange, handler);    }    public event EventHandler<TemperatureArgs> OnTemperatureChange    {        add { add_OnTemperatureChange(value); }        remove { remove_OnTemperatureChange(value); }    }*/}//自訂事件的實現public class Thermostat3{    protected EventHandler<TemperatureArgs> onTemperatureChange;    public event EventHandler<TemperatureArgs> OnTemperatureChange    {        add        {            //最後註冊的訂閱者,在通知時被第一個通知            Delegate.Combine(value, onTemperatureChange);        }        remove { Delegate.Remove(onTemperatureChange, value); }    }}/// <summary>/// 調整器,用於控制加熱器與製冷器的開關/// </summary>public class Adjust{    public Adjust(string controllerName, float temperature, Func<float, float, bool> predicate)    {        ControllerName = controllerName;        Temperature = temperature;        predicateSwitch = predicate;    }    /// <summary>    /// 控制器名稱,可以是製冷器、或加熱器    /// </summary>    public string ControllerName { get; set; }    public float Temperature { get; set; }    public Func<float, float, bool> predicateSwitch { get; private set; }    public void OnTemperatureChange(object sender, TemperatureArgs eArgs)    {        Console.WriteLine("{0} : {1}", ControllerName, predicateSwitch(Temperature, eArgs.NewTemprature) ? "On" : "Off");    }}
View Code

C#學習筆記9

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.