回呼(callback)函數是Windows程式設計的重要部分。如果您具備C或C++程式設計背景,就曾在許多Windows API中使用過回呼。 VB加入了AddressOf關鍵字後,開發人與就可以利用以前一度收到限量的API了。回調函數實際上是方法呼叫的指針,也稱為函數指針,是一個非常強大的程式設計特性。 .NET以委託的形式實現了函數指標的概念。它們的特殊之處是,與C函數指標不同,.NET委託是類型安全的。這說明,C中的函數指針只不過是一個指向存儲單元的指針,我們無法說出這個指針實際上指向什麼,像參數和返回類型等就更無從知曉了。如本章所述,.NET委託作為一種類型安全的操作。以下我們將學習.NET如何將委託用作實現事件的方式。
一、委託
當要把方法傳送給其他方法時,就需要使用委託。要了解他們的含義,可以看看下面的程式碼:
int i = int.Parse("99");
我們習慣於吧資料作為參數傳遞給方法,如上面的例子所示。所以,給方法傳送另一個方法聽起來有點奇怪。而有時某個方法執行的操作並不是針對資料進行的,而是要對另一個方法進行操作,這就比較複雜了。在編譯時我們不知道第二個方法是什麼,這個資訊只能在運行時得到,所以需要把第二個方法作為參數傳遞給第一個方法,這聽起來很令人迷惑,下面幾個實例來說明:
1.啟動線程-----在C#中,可以告訴電腦並行運行某些新的執行序列。這種序列稱為線程,在累積System.Threading.Thread的一個實例上使用方法Start(),就可以開始執行一個執行緒。如果要告訴電腦開始一個新的執行序列,就必須說明要在哪裡執行該序列。必須為電腦提供開始執行的方法的細節,即Thread.Start()方法必須帶有一個參數,該參數定義了要由執行緒呼叫的方法。
2、通用函式庫類別------有許多函式庫包含執行各種標準任務的程式碼。這些庫通常可以自我包含。這樣在寫函式庫時,就會知道任務如何執行。但是有時在任務中還包含子任務。只有使用該庫的客戶機程式碼才知道如何執行這些子任務。例如寫一個類,它帶有一個物件數組,並把它們按升序排列。但是,排序的部分過程會涉及到重複使用數組中的兩個對象,比較他們,看看哪一個應該放在前面。如果要編寫的類別必須能為任何物件數組排序,就無法事先告訴計算機應如何比較物件。處理類別中物件陣列的客戶機程式碼也必須告訴類別如何比較要排序的物件。換言之,客戶機程式碼必須給類別傳遞某個可以進行這種比較合適的細節。
3、事件------一般是通知代碼發生了什麼事件。 GUI程式設計主要是處理事件。在發生事件時,運行庫需要知道應執行哪個方法。這就需要把處理時間的方法傳送為委託的一個參數。這些將在後面討論。
前面建立了有時會把方法名稱當作參數傳遞給其他方法的規則。下面需要指出如何完成這個過程。最簡單的方式就是把方法名稱當作參數傳遞出去。例如在前面的線程範例中,假定要啟動一個新線程,且有一個叫作EntryPoint()的方法,該方法是開始執行線程時的地方。
void EntryPoint()
{
//do whatever the new thread needs to do
}
也可以用下面的程式碼開始執行新執行緒:
Thread NewThread = new Thread();
Thread.Start(EntryPoint); //WRONG
實際上,這是一種很簡單的方式,在某些語言如C和C++中使用的就是這種方式(在C和C++中,參數EntryPoint是一個函數指標)。
但這種直接的方法會導致一些問題,例如類型的安全性,在進行物件導向程式設計時,方法很少是孤立存在的,在呼叫前,通常需要與類別實例相關聯。而這種方法並沒有考慮到這個問題。所以.NET Framework在語法上不允許使用這種直接的方法。如果要傳遞方法,就必須把方法的細節封裝在一種新類型的物件中,也就是委託。委託只是一種特殊的物件類型,其特殊之處在於,我們先前定義的所有的物件都包含數據,而委託包含的只是方法的細節。
-