1. 程式人生 > >C#中委託(delegate)和多播委託的理解

C#中委託(delegate)和多播委託的理解

委託

委託是定址方法的.NET版本。

什麼是定址方法? 簡單理解為我們通過委託傳遞一個方法給另一個方法。

什麼時候需要傳遞方法?微軟的官方文件C#高階程式設計(第七版)這本書都提到一個例子-----在物件的排序演算法中,需要對物件進行比較,而不同物件比較的方法不同,所以比較兩個物件的方法的引用可以作為引數傳遞到排序演算法中,這個時候就需要傳遞方法。

通過什麼傳遞方法?

在理解委託的時候經常將其與C++中的函式指標做比較,函式指標只是一個指向記憶體位置的指標,它不是型別安全的,我們無法判斷這個指標實際指向什麼,引數和返回型別更加無從知曉。但我們可以通過該函式指標獲得該方法也可以理解為通過傳遞地址來傳遞該方法

; 函式指標是面向過程的,而C#是面向物件程式設計,幾乎沒有方法是孤立存在的,而是在呼叫方法之前需要與類的例項相關聯。 所以.NET框架不允許使用函式指標這種直接的方法,因為這這很不面向物件! 那如何才符合面向物件的核心價值觀?—————— 委託 在C#中要傳遞方法,就必須把方法的細節封裝在一種新型別的物件中,即委託。委託只是一種特殊型別的物件,其特殊之處在於,我們定義的所有物件都包含資料,而委託包含的只是一個或多個方法的地址。

總結

委託是一種引用型別,表示對具有特定引數列表和返回型別的方法的引用。 在例項化委託時,你可以將其例項與任何具有相容簽名和返回型別的方法相關聯。 你可以通過委託例項呼叫方法。 委託用於將方法作為引數傳遞給其他方法。 這符合.NET規範,對比函式指標

,委託 是面向物件的、型別安全的和可靠的,但也損失了靈活性!

宣告一個委託:

public delegate int operation(int num1, int num2);

該委託表示的方法有倆個int型別的引數,返回值也為int型別。 要注意的是其語法類似於方法的定義,但沒有方法體,關鍵字為delegate。 定義委託相當於定義一個新類(其實還真是定義一個類),所有定義的位置可以是在定義類的任何相同的地方,可以在類的內部或者外部定義。

可以例項該委託的方法(即方法的引數和返回值和委託一致): 也可以說是可以被該委託封裝的方法

       // Create  methods for a delegate.
       public int add(int num1,int num2) 
        {
            return num1 + num2;
        }
        public int reduce(int num1, int num2)
        {
            return num1 - num2;
        }

例項委託: 在官方文件和高階程式設計書中可以看到兩種例項方法:

operation someoperation = new operation(reduce);//法一:通過在委託的建構函式中新增委託引用的方法
//operation someoperation = add;//法二:直接讓委託物件等於引用的方法

呼叫委託:

       someoperation (num1,num2);

注意: 因為委託的例項為一個物件所有,可以作為一個方法的引數:

      public int numMethod(int num1, int num2, operation callback)
        {
            return callback(num1,num2);
        }

並且我們可以將委託的例項傳入該方法,也可以直接將方法傳入

            operation someoperation = new operation(reduce);
            int result = numMethod(2, 1, someoperation);//法一:傳入委託例項
            //int result = numMethod(2, 1, reduce);//法二:直接傳入方法

多播委託

委託可以呼叫多個方法。 這被稱為多播。 若要向委託的方法列表(呼叫列表)新增其他方法,只需使用加法運算子或加法賦值運算子(“+”或“+=”)新增兩個委託,也可以通過(“-”或“-=”)去除委託。 例如:

MethodClass obj = new MethodClass();
Del d1 = obj.Method1;
Del d2 = obj.Method2;
Del d3 = obj.Method3;

//新增多個委託
Del allMethodsDelegate = d1 + d2;
allMethodsDelegate += d3;
------------------------------------------
//去除委託的方法
allMethodsDelegate -= d1;

// copy AllMethodsDelegate while removing d2
Del oneMethodDelegate = allMethodsDelegate - d2;

注意3個方法都是該委託可以封裝的方法,且多播委託封裝的方法返回值必須都為void,不然只能得到呼叫最後一個方法的結果。

最後: 多播委託廣泛用於事件處理中。 事件源物件將事件通知傳送到已註冊接收該事件的接收方物件。 若要註冊一個事件,接收方需要建立用於處理該事件的方法,然後為該方法建立委託並將委託傳遞到事件源。 事件發生時,源呼叫委託。 然後,委託將對接收方呼叫事件處理方法,從而提供事件資料。 給定事件的委託型別由事件源確定。