程序世界有兩種神秘的元素,它們無處不在,卻常常未被察覺。它們一動一靜,卻又和諧相處。我給 這對兄弟取上不太恰當的名字,一個叫“協議”,一個叫“約束”。我們常常看到的動態語言、靜態語言 背後,本質上就是“協議”與“約束”兩種元素的作用。靜態語言和動態語言本身沒有一個明確的界限, 它們各有優勢,又各有不足。
C#是一門優美的語言,它融合了靜態和動態的優勢,如果運用得當,必能動靜結合,呈現出一種和諧 之美。特別是.NET平台和語言的快速發展,更展現了動靜結合編程的活力。本篇是.NET動靜結合編程的第 一篇,希望這個系列能和大家一起探討如何在.NET平台上最大限度的發揮動靜結合的潛能。本人還只 是.NET的初學者,對計算機理論的理解還很膚淺,文中錯誤歡迎批評指正,不足之處歡迎補充,謝謝!
被忽略的協議
談到“協議”,最先浮現在我們腦海中的可能是TCP/IP協議棧,但其實我們隨處都在和協議打交道。 下面的例子,你看出協議來了嗎?
B(){
ArrayList lst = A();
foreach (string item in lst){
Console.WriteLine(item.Length);
}
}
方法B假定方法A遵守:返回的ArrayList內部都是string類型的元素。這就是它們之間的協議,這個協 議不受編譯器靜態檢查的約束。所以,協議意味著運行時的不確定性,方法A完全可能在返回結果中裝入 非string類型的元素,而這將導致B在運行時產生異常。
.NET2.0通過泛型集合增加了靜態類型約束:
B(){
List<string> lst = A();
foreach (string item in lst){
Console.WriteLine(item);
}
}
這樣,B再也不用擔心lst內部存在非string類型的元素了,一切得益於泛型為A加上的靜態類型約束。
約束有強弱
約束有強弱之分。越強的約束越安全,靜態性越強,受編譯器的支持越大;反之,越弱的約束,動態 性越強,運行時靈活性越大。
常常看到關於單方法接口和委托異同的討論,不少朋友認為它們完全等價。其實,它們有明顯不同的 約束強度。接口是靜態類型約束,而委托只是靜態簽名約束,二者的強度完全不同。換句話說,委托具有 更多的協議性,只要符合簽名,都可以被委托調用,而能被接口調用的對象必須實現該接口。
來看一個例子:需要編寫一個類A,其內部需要日志功能;A采用IoC方式,不依賴於具體的Logger類, 由使用者根據需要注入具體的實現;同時,A的使用者B,希望采用第三方的Logger類。
a. 基於接口的IoC
interface ILogger { void Write(string msg); }
class A{
ILogger Logger { get; set; }
void F() {}
}
class B{
G(){
A a = new A();
a.Logger = new LogAdapter(); //注入依賴
a.F();
}
}
//對第3方Logger進行包裝
class LogAdapter : ILogger{
Write(string msg){//這裡調用第3方的Logger類}
}
b. 基於委托的IoC
class A{
Action<string> Logging { get; set; }
void F() {}
}
class B{
G(){
A a = new A();
a.Logging = delegate(string msg){ //調用第3方Logger類 };
a.F();
}
}
比較上面兩個例子,我們就會發現委托比接口的約束要弱得多,使用起來靈活得多。基於接口的實現 不得不增加一個Adapter去機械地適應接口的類型約束,而基於委托的實現只需要保證方法簽名約束即可 。
後續
後續章節打算陸續介紹DuckTyping、泛型委托妙用、表達式樹和lambda、.NET4.0動態編程等相關內容 ,敬請關注,多謝批評!