回調函數
回調函數的確是至今為止最有用的編程機制之一。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)數組並初始化每一個整型值。