程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#學習筆記9

C#學習筆記9

編輯:C#入門知識

C#學習筆記9。本站提示廣大學習愛好者:(C#學習筆記9)文章只能為提供參考,不一定能成為您想要的結果。以下是C#學習筆記9正文


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
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved