回調函數
回調函數的確是至今為止最有用的編程機制之一。C運行時的qsort函數利用回調函數對數組元素進行排序。在Windows中,回調函數更是窗口過程,鉤子過程,異步過程調用,以及目前Microsoft .NET框架所必需的,在整個回調過程中自始至終地使用回調方法。人們可以注冊回調方法以獲得加載/卸載通知,未處理異常通知,數據庫/窗口狀態修改通知,文件系統修改通知,菜單項選擇,完成的異步操作通知,過濾一組條目等等。
在C/C++中,一個函數的地址就是內存地址。這個地址不會附帶任何其它賦加信息,如函數的參數個數,參數類型,函數的返回值類型以及這個函數的調用規范。簡言之,C/C++回調函數不是類型安全的。
在.NET框架中,回調函數所受到的重用與它在Windows非受控編程中一樣。不同的是在.NET框架中提供了一種叫委派(delegates)的類型安全機制。我們先來研究一下委派的聲明。下面的代碼展示了如何聲明,創建和使用委派:
// using System; using System.WinForms; // 在beta2版本中為:System.Windows.Forms using System.IO; class Set { private Object[] items; public Set(Int32 numItems) { items = new Object[numItems]; for (Int32 i = 0; i < numItems; i++) items[i] = i; } // 定義 Feedback,類型為delegate // (注意: 這個類型在Set類中是嵌套的) public delegate void Feedback( Object value, Int32 item, Int32 numItems); public void ProcessItems(Feedback feedback) { for (Int32 item = 0; item < items.Length; item++) { if (feedback != null) { // 一旦指定了回調,便調用它們 feedback(items[item], item + 1, items.Length); } } } } class App { [STAThreadAttribute] static void Main() { StaticCallbacks(); InstanceCallbacks(); } static void StaticCallbacks() { // 創建一個Set對象,其中有五個項目 Set setOfItems = new Set(5); // 處理項目,feedback=null setOfItems.ProcessItems(null); Console.WriteLine(); // 處理項目,feedback=Console setOfItems.ProcessItems(new Set.Feedback(App.FeedbackToConsole)); Console.WriteLine(); // 處理項目,feedback =MsgBox setOfItems.ProcessItems(new Set.Feedback(App.FeedbackToMsgBox)); Console.WriteLine(); // 處理項目,feedback = console AND MsgBox Set.Feedback fb = null; fb += new Set.Feedback(App.FeedbackToConsole); fb += new Set.Feedback(App.FeedbackToMsgBox); setOfItems.ProcessItems(fb); Console.WriteLine(); } static void FeedbackToConsole( Object value, Int32 item, Int32 numItems) { Console.WriteLine("Processing item {0} of {1}: {2}.", item, numItems, value); } static void FeedbackToMsgBox( Object value, Int32 item, Int32 numItems) { MessageBox.Show(String.Format("Processing item {0} of {1}: {2}.", item, numItems, value)); } static void InstanceCallbacks() { //創建一個Set對象,其中有五個元素 Set setOfItems = new Set(5); // 處理項目,feedback=File App appobj = new App(); setOfItems.ProcessItems(new Set.Feedback(appobj.FeedbackToFile)); Console.WriteLine(); } void FeedbackToFile( Object value, Int32 item, Int32 numItems) { StreamWriter sw = new StreamWriter("Status", true); sw.WriteLine("Processing item {0} of {1}: {2}.", item, numItems, value); sw.Close(); } } //注意代碼最上面的Set類。假設這個類包含一組將被單獨處理的項目。當你創建Set對象時,將它要操縱的項目數傳遞給它的構造函數。然後構造函數再創建對象(Objects)數組並初始化每一個整型值。