不過我支援,為什麼?因為我也提過出這樣的問題。
這樣,我們暫且不提應聘“進階開發人員”的人,在“自稱熟悉各版本.NET架構”的前提下,是否應該知道這個答案。我們也暫且不提Michael同學提問的“目的”是什麼。老趙就先單獨針對這個問題進行解釋,然後談談自己為什麼會提出這個問題吧。
可能有一件事情需要說在前面,那就是:委托本身其實從來沒有改變過,改變的一直都是委托的“寫法”。是以更确切地說,改變的隻是“編譯器”。而本文所有内容都用C#來實作,其實談得也都是C#編譯器本身——但是其實VB.NET也有變化啊。再由于.NET版本和C#版本的關系也是非常密切的,是以全文就使用.NET版本進行指代了。
委托,如果不追究細節,從表面上來看我們可以将其通俗地了解為一個安全的“函數指針”。當然,這個函數指針其實也是一個對象,有自己的成員,也會封裝了被調用方的上下文等等。至于委托的定義和使用方式,則是這樣的:
可見,在.NET 1.x中需要使用new DelegateType(...)的方式來建立一個委托對象。不過,作為委托對象内部的方法它既可以是執行個體方法,也可以是靜态方法。此外,方法隻需要比對委托類型的簽名和傳回值即可,方法參數的名稱不會成為限制。
嗯,就是這麼簡單。
.NET中的委托引入了範型,且寫法略有簡化:
在.NET 2.0中,new DelegateType已經可以省略,開發人員可以直接将方法指派給一個委托對象的引用。當然,這個改進不值一提,.NET 2.0中委托寫法的關鍵在于引入了“匿名方法”:
匿名方法,簡單地說就是内聯在方法内部的委托對象,它的關鍵便在于形成了一個閉包(委托執行時所需的上下文)。如上面的代碼中,BeginGetResponse的第一個參數(委托)可以直接使用TestRequest方法的參數url,以及方法内的“局部”變量request。如果沒有匿名函數這個特性的話,代碼寫起來就麻煩了,例如在.NET 1.x中您可能就必須這麼寫:
此時,我們往往會發現,開發人員需要花費大量的精力,為一小部分代碼維護一大段上下文。例如在這段代碼中,我們會将url和request對象塞入一個object數組中,在回調函數中再通過危險的Cast操作恢複資料。如果您希望“強類型”,那麼隻能為每個回調建立一個新的上下文對象,維護起來可能更加麻煩——要知道,在并行程式設計,異步調用越來越重要的今天,如果沒有匿名方法自動保留上下文的特性,開發人員會為這些“額外工作”疲于奔命的。
可能您會說,匿名方法的可讀性不佳,因為需要“内聯”。一個方法中内聯太多,維護成本就上去了,是以匿名方法并不推薦使用。我想說的是,您錯了。如果為了可維護性,要将方法獨立拆開,也可以利用匿名方法的優勢:
如果借助.NET 3.5中的Lambda表達式,代碼可以寫的更簡單易讀:
千萬不要小看匿名方法的作用,有些時候您認為它的作用僅限于上文描述,隻是因為沒有在某些問題上踏前一步。例如,對于那些隻需要“按需建立”,且要“線程安全”的對象,您會怎麼做呢?沒錯,可以使用Double Check:
嗯,做的很漂亮!那麼……這樣的屬性再來一個,再來三個,再來五個呢?可能有些朋友就會開始大段地Copy & Paste,于是錯誤便難免了。這裡有一件真人真事,以前某位同學在一堆這樣的代碼中迷茫了,說為什麼用了這種方法,還是初始化了多次對象了?檢查了半天沒有看出問題來。最後發現,原因是通路了錯誤的initialized變量(例如,在某個應該通路artistInitialized的地方通路了articleInitialized)。可惜,大段時間已經被浪費了——更糟的是,心情也随之變差了。
其實,Copy & Paste很明顯沒有遵守DRY原則啊。為什麼不把它們封裝在一處呢?例如:
于是,之前的代碼就可以簡化成這樣了:
還是太醜,上Lambda表達式!
至于Lambda表達式以及其他話題,我們下次再說吧。
您現在還覺得.NET中的“委托”是一個簡單的,隻适合“初學者”,一搜就都知道的概念嗎?
您可能會說“是”,不過對我來說這真不簡單,我也是慢慢才意識到這些的。雖然關于委托的大量内容可以在網際網路上搜尋而來,但還是有太多東西是需要在大量程式設計實踐中積累下來的——等一下,這不就是“進階開發人員”和“初學者”的主要差別之一嗎?
嘲笑孔乙己的朋友們,你們在一味鄙視“茴”的四種寫法的同時,說不定也失去了一個了解中國傳統文化的機會呢!
剩下的下次再說吧,Lambda表達式還等着我們。
從.NET中委托寫法的演變談開去(上):委托與匿名方法
<a href="http://kb.cnblogs.com/page/69348/" target="_blank">從.NET中委托寫法的演變談開去(中):Lambda表達式及其優勢</a>
<a href="http://kb.cnblogs.com/page/69350/" target="_blank">從.NET中委托寫法的演變談開去(下):性能相關</a>