星期一, 5月 07, 2007

delegate

delegate 是 C# 中宣告函式形態的機制。也就是說,我們可以自訂一種型態,用來儲存一個函式。這樣一來,我們就能把函式當成參數,在 function﹝method﹞ 之間傳遞。


在 C++ 中,是以 pointer to function 實踐,而函式引數稱之為 function object ﹝functor﹞。就這方面來說,C++ 比起 C# 要來的複雜些,但在概念上大同小異。

至於 delegate 的功用,主要在實踐 function 多樣性的同時,仍維護住 encapsulation。也就是說,不論外部有何更動,都不影響到這些 function 的運作﹝function 內容仍維持不變﹞。

思考以下狀況:沒有函式引數之前,要以一個 sort function 針對不同比對規則排序,該如何做?一個可行的方法是這樣的:先定義好許多 compare function,並給每個 compare function 相對應的代號(字元或整數)。而在使用此 sort function 時,多傳遞一作為代號的參數,而 sorting 時就根據此代號判斷要用哪個 compare function 來 sorting。如此一來,就能達到目的 - 一個 sort function 能針對不同比對規則做排序。

然而,這樣的方式有個重大的缺點:當我們創造出一新的比對方式時(也就是增加了一個代號),我們必須更改原函式(例:增加一個 if),讓它能識別此代號,並使用對應的 compare function 做排序。這樣一來,一旦有新的比對方式產生,不僅原程式需要更改,連 sort function 內部也必須更動,而這大大增加了 maintain 的難度。

因此,我們希望能有一種方法,不論增加了多少比對方式,原 sort function 都能維持不變,而 delegate 正回應了此要求。

delegate 的語法如下:

delegate return_type function_type_name ( parameter );


定義完 function_type 之後,就能以此 function_type 宣告 function 變數。只要某 function return type及 parameter 與 function_type 中的一致,此 function 就能被儲存在此變數中。因此,以 sort function 排序時,只要傳遞此 function_type 的變數,不必經由 if 判斷,就能得知要以哪個 compare function 來 sorting。

舉個例子,假設有個 sort function 要對字串排序,則我們的 compare function_type 應該如下:

delegate bool strcmp (string s1, string s2);


又假設我們有以下幾種 compare function:

bool ascii_cmp (string s1, string s2) { //... }
bool size_cmp (string s1, string s2) { //... }
bool other_cmp (string s1, string s2) { //... }


由於 ascii_cmp、size_cmp、other_cmp 的 return_type 及 parameter 都與 strcmp 一致,它們都可以被儲存在由 strcmp 宣告出的變數之中,如:

strcmp cmp1 = new strcmp (ascii_cmp);
strcmp cmp2 = new strcmp (size_cmp);
strcmp cmp3 = new strcmp (other_cmp);


接著,我們只要讓 sort function 能接收一 strcmp type 的變數,就能達成我們要的比對規則,如下(以簡單的 bubble sort為例):

void string_sort (string[] array, strcmp cmp) {
for (int i = 0 ; i < array.Length ; ++i) {
for (int j = 0 ; j < array.Length - i - 1 ; ++j) {
if (cmp (array[j], array[j + 1]))
swap (ref array[j], ref array[j + 1])
}
}
}


從以上可知,使用 function_type 宣告出的變數就如同使用一般 function。

沒有留言: