委託及觀察者模式

2023-06-25 15:00:39

委託

委託(delegate)是一種特殊的型別(class),它可以被認為是一個可以擁有函數參照的類,它的宣告規定了它能夠持有的函數參照的函數形式,同時它可以儲存多個函數參照,並通過自己的方法呼叫所有註冊在它身上的方法(釋出者)。

理解了觀察者模式就理解了委託

它的特點在於:

  1. 委託型別的定義方式通過特定關鍵字 delegate 來定義,而不是 class

  1. 我們無法為委託型別定義方法,它繼承固定的類有固定的方法,這是發生在語言底層的

  1. 一個委託型別的變數時可以像一個普通型別的變數一樣宣告,但更好的方式是使用 event 關鍵字來修飾委託型別的變數,event 關鍵字包裝了委託型別的變數(事件變數不是委託變數,它們是兩個東西,儘管它們在宣告方式上很像,事件變數包裝了一個委託變數),這將避免從類外控制這個事件的釋出(Invoke
namespace InterfaceTest
{
    [TestClass]
    public class DelegateTest
    {
        // 一個自定義的委託型別的變數,類比自定義的類的變數
        public event Function calc;

        [TestMethod]
        public void TestMethod1()
        {
            calc += () =>
            {
                return 0.0;
            };
            calc += DelegateTest.C;
            calc += new Function(C);
            calc = calc + C;
            calc.Invoke();
        }

        public static double C() { return 1.0;  }
    }

    // 委託是一個型別,所以它可以直接定義在名稱空間下
    // 無法為委託型別自定義方法
    public delegate double Function();

    public class Caller
    {
        public Caller()
        {
            var dt = new DelegateTest();
            // 由於calc是一個event修飾的屬性,所以從外部呼叫Invoke將引發異常
            dt.calc.Invoke(); // ERROR
        }
    }
}

  1. 就像我們可以直接使用語言本身提供的 string 型別一樣,我們也可以直接使用語言本身提供的 ActionFunc 委託型別,它們已經包含了絕大多數可能的函數簽名的形式,而無需自定義自己的 「MyString」

委託及觀察者模式

在觀察者模式中主要有四個事物:釋出者、訂閱者、「訂閱」過程、「釋出」過程。

釋出者主要包含一個儲存了訂閱者參照的集合,在「釋出過程」發生時,通過這個訂閱者所持有的參照呼叫實現了相同介面的訂閱者的方法(在這一步有多種方式,不一定非要是介面,目的在於使釋出者能夠通過多型統一儲存所有的訂閱者,從而在「釋出」時遍歷整個集合呼叫所有訂閱者的方法。關於其它的實現方式可見參照.6)。

在委託中,觀察者模式的這四個部分的實現如下:

  • 釋出者:委託型別的變數

  • 訂閱者:符合委託型別定義的函數簽名的函數,表現形式有lambda表示式、直接定義的函數等(將函數當作一個函數型別的範例)

  • 「訂閱」:+ -,常見的形式是 += -=,本質上是委託型別過載了 +- 運運算元

  • 「釋出」:

    1. 由系統負責「釋出」,程式設計師提供釋出時的動作(委託型別的函數):例如,WPF或Winform後置程式碼中的事件響應函數

    2. 由程式設計師負責「釋出」,系統負責提供釋出時的動作:例如,WPF中的OnPropertyChanged 在ViewModel中手動呼叫,但它上的函數的註冊在XAML解析時完成

參照

  1. 《C#圖解教學》
  2. 劉鐵猛. C#語言入門詳解
  3. learn.microsoft 如何組合委託
  4. MulticastDelegate.cs
  5. Delegate.cs
  6. 觀察者模式