委托背后的故事
學習過.NET的都知道,C#中引入了一種新的類型Delegate,也就是我們經常說的委托。委托到底是什么,大家都說它類似於指針,但是要比這些指針要安全。那么為什么要引入這個委托呢,今天我們就來看看委托的這點事兒!
委托前的蠻荒時代
我們大家都知道C語言中有一種很強大的武器就是指針,指針一個比較大的用處就是允許我們手動操作內存,這個是與托管代碼的高級語言是一個主要的差別。我們都知道數據變量的內存地址可以存儲在相應的指針變量中,同樣函數的首地址也可以存儲在某個函數指針變量里的。這樣我們就可以通過這個函數指針變量來調用其所指向的函數了。一般情況下我們使用函數指針的情景如下代碼所示,我們很少會直接將函數指針作為函數參數傳遞,但是有時候我們想在一個方法里調用客戶傳遞的函數,通知客戶我們進行了某項操作,以便讓客戶進行相應的業務操作。具體代碼我就不給出了,老長時間不接觸C都快忘光了,有興趣的話可以自己查閱相關的資料。
void (*FunP)( int ); // 也可申明成void(*FunP)(int x),但習慣上一般不這樣。
int main( int argc, char* argv[])
{
MyFun( 10); // 這是直接調用MyFun函數
FunP=&MyFun; // 將MyFun函數的地址賦給FunP變量
(*FunP)( 20); // 這是通過函數指針變量FunP來調用MyFun函數的。
}
void MyFun( int x) // 這里定義一個MyFun函數
{
printf(“%d\n”,x);
}
如果你感覺在C語言中傳遞函數作為參數沒有什么應用市場,那么它在javascript中卻無處不在,比如我們想在頁面加載完成以后執行我們的業務邏輯,這個時候我們可以將封轉了我們業務邏輯的函數,直接綁定到window的onload事件上,代碼如下,這就是我們軟件開發中最活躍的事件模型,不管是前台界面編程還是后台框架編程,事件模型都是十分有用的。
// 我們自己的業務邏輯
};
window.onload = pageLoadHandler;
如果你了解javascript面向對象編程,那么下邊的代碼你一定不會陌生,代碼中我們為數組對象擴展了一個select函數,其根據客戶傳入的函數篩選所需的元素。你現在對這段代碼是否感到似曾相識,如果還沒有,就繼續接着看下邊的調用示例代碼。對這跟C#中的拉姆達表達式很像,其實更應該說,前者像后者。
var result = new Array();
for ( var index = 0; index < this.length; i++) {
if (filter.call( this, index, this[index])) {
result.push( this[index]);
};
};
return result;
};
var array = new Array();
array.push(1);
array.push(2);
array.push(3);
var selectedArray = array.select( function (index, item) {
var result = false;
if (item > 1) {
result = true;
};
return result;
});
面向對象時代的委托
隨着軟件規模的不斷擴大和軟件開發方法學的發展,面向對象開發逐漸的取代了面向過程的開發。我們知道面向對象中的基本單位是對象,對象是數據和操作的組合體,對象封轉了數據和操作,所有對數據和操作的調用都要經過對象進行交互。這樣的話,很顯然我們不能將函數直接作為參數傳遞了。作為一種新生代的語言,C#除了引入一些新的特性之外,同時也需要兼容一些已經存在的技術。那這個時候我們怎么辦呢?
我們都知道既然方法都依附於某個對象,那么我們就可以定義一個類,來記錄方法的相關信息,這樣不僅保證了方法的唯一性,同時也提高了代碼的安全性。所以在C#中引入了委托,委托是一種定義方法簽名的類型。當實例化委托時,可以將其實例與任何具有兼容簽名的方法相關聯。我們可以通過委托實例調用方法。委托用於將方法作為參數傳遞給其他方法。事件處理程序就是通過委托調用的方法。您可以創建一個自定義方法,當發生特定事件時某個類(例如Windows 控件)就可以調用我們的方法。
{
// 摘要:
// 初始化一個委托,該委托對指定的類實例調用指定的實例方法。
//
// 參數:
// target:
// 類實例,委托對其調用 method。
//
// method:
// 委托表示的實例方法的名稱。
//
// 異常:
// System.ArgumentNullException:
// target 為 null。 - 或 - method 為 null。
//
// System.ArgumentException:
// 綁定到目標方法時出錯。
protected Delegate( object target, string method);
//
// 摘要:
// 初始化一個委托,該委托從指定的類調用指定的靜態方法。
//
// 參數:
// target:
// System.Type,它表示定義 method 的類。
//
// method:
// 委托表示的靜態方法的名稱。
//
// 異常:
// System.ArgumentNullException:
// target 為 null。 - 或 - method 為 null。
//
// System.ArgumentException:
// target 不是 RuntimeType。請參見反射中的運行庫類型。 - 或 - target 表示開放式泛型類型。
protected Delegate(Type target, string method);
}
總結
其實,所謂委托就是在面向開發對象領域中,對傳遞函數作為參數的實現方式。它記錄了方法所依附的對象及方法的相關信息。