SharpDevelop代碼分析 (一、序+基本概念)
2024-07-21 02:21:21
供稿:網(wǎng)友
 
序
 最近開始學(xué)習(xí).net,遇到了一個(gè)比較不錯(cuò)的開源的ide sharpdevelop。這個(gè)開發(fā)工具是使用c#開發(fā)的,比較吸引我的一點(diǎn)就是它是采用了和eclipse類似的插件技術(shù)來(lái)實(shí)現(xiàn)整個(gè)系統(tǒng)的。而這個(gè)插件系統(tǒng)是我最感興趣的地方,因此開始了一段代碼的研究。在本篇之后,我會(huì)陸續(xù)把我研究的心得寫下來(lái)。由于是在網(wǎng)吧上網(wǎng),有諸多不便,因此可能會(huì)拖比較長(zhǎng)的時(shí)間。
一、基本概念
 首先,我們先來(lái)對(duì) sharpdevelop 有一個(gè)比較感性的認(rèn)識(shí)。你可以從這里下載到它的可執(zhí)行程序和代碼包 http://www.icsharpcode.com/ ,安裝的廢話就不說了,先運(yùn)行一下看看。感覺跟vs很像吧?不過目前的版本是1.0.0.1550,還有很多地方需要完善。關(guān)于代碼和系統(tǒng)結(jié)構(gòu),sharpdevelop的三個(gè)作者寫了一本書,各位看官可以參考一下,不過我看過之后還是有很多地方不太理解。
 然后,讓我來(lái)解釋一下什么叫插件以及為什么要使用插件系統(tǒng)。我們以往的系統(tǒng),開發(fā)人員編譯發(fā)布之后,系統(tǒng)就不允許進(jìn)行更改和擴(kuò)充了,如果要進(jìn)行某個(gè)功能的擴(kuò)充,則必須要修改代碼重新編譯發(fā)布。這就給我們帶來(lái)了比較大的不方便。解決的方法有很多,例如提供配置等等方法。在解決方案之中,插件是一個(gè)比較好的解決方法。大家一定知道photoshop、winamp吧,他們都有“插件”的概念,允許其他開發(fā)人員根據(jù)系統(tǒng)預(yù)定的接口編寫擴(kuò)展功能(例如photoshop中各種各樣的濾鏡)。所謂的插件就是系統(tǒng)的擴(kuò)展功能模塊,這個(gè)模塊是以一個(gè)獨(dú)立文件的形式出現(xiàn)的,與系統(tǒng)是相對(duì)獨(dú)立。在系統(tǒng)設(shè)計(jì)期間并不知道插件的具體功能,僅僅是在系統(tǒng)中為插件留下預(yù)定的接口,系統(tǒng)啟動(dòng)的時(shí)候根據(jù)插件的配置尋找插件,根據(jù)預(yù)定的接口把插件掛接到系統(tǒng)中。
 這樣的方式帶來(lái)什么樣的優(yōu)點(diǎn)呢?首先是系統(tǒng)的擴(kuò)展性大大的增強(qiáng)了,如果我們?cè)谙到y(tǒng)發(fā)布后需要對(duì)系統(tǒng)進(jìn)行擴(kuò)充,不必重新編譯,只需要修改插件就可以了。其次有利與團(tuán)隊(duì)開發(fā),各個(gè)功能模塊由于是以插件的形式表現(xiàn)在系統(tǒng)中,系統(tǒng)的每日構(gòu)造就很簡(jiǎn)單了,不會(huì)因?yàn)槟硞€(gè)模塊的錯(cuò)誤而導(dǎo)致整個(gè)系統(tǒng)的build失敗。失敗的僅僅是一個(gè)插件而已。
 photoshop和winamp的插件系統(tǒng)是比較簡(jiǎn)單的,他們首先實(shí)現(xiàn)了一個(gè)基本的系統(tǒng),然后在這個(gè)系統(tǒng)的基礎(chǔ)上掛接其他擴(kuò)展的功能插件。而sharpdevelop的插件系統(tǒng)更加強(qiáng)大,它的整個(gè)系統(tǒng)的基礎(chǔ)就僅僅是一個(gè)插件管理系統(tǒng),而你看到的所有的界面、功能統(tǒng)統(tǒng)都是以插件的形式掛入的。在這樣的一個(gè)插件系統(tǒng)下,我們可以不修改基本系統(tǒng),僅僅使用插件就構(gòu)造出各種各樣不同的系統(tǒng)。
 現(xiàn)在讓我們來(lái)看看它的插件系統(tǒng)。進(jìn)入到sharpdevelop的安裝目錄中,在bin目錄下的sharpdevelop.exe 和 sharpdevelop.core.dll是這個(gè)系統(tǒng)的基本的插件系統(tǒng)。在addins目錄下有兩個(gè)后綴是addin的文件,其中一個(gè) sharpdevelopcore.addin 就是它的核心插件的定義(配置)文件,里面定義的各個(gè)功能模塊存在于bin/sharpdevelop.base.dll 文件中,另外還有很多其他的插件定義在addins目錄下的addin文件中。
 分析sharpdevelop的代碼,首先要弄清楚幾個(gè)基本的概念,這些概念和我以前的預(yù)想有一些區(qū)別,我深入了代碼之后才發(fā)現(xiàn)我的困惑所在。
1、addintree 插件樹
 sharpdevelop 中的插件被組織成一棵插件樹結(jié)構(gòu),樹的結(jié)構(gòu)是通過 extension(擴(kuò)展點(diǎn))中定義的path(路徑)來(lái)定義的,類似一個(gè)文件系統(tǒng)的目錄結(jié)構(gòu)。系統(tǒng)中的每一個(gè)插件都在配置文件中指定了 extension,通過extension中指定的 path 掛到這棵插件樹上。在系統(tǒng)中可以通過 addtreesingleton對(duì)象來(lái)訪問各個(gè)插件,以實(shí)現(xiàn)插件之間的互動(dòng)。
2、 addin 插件
 在 sharpdevelop 的概念中,插件是包含多個(gè)功能模塊的集合(而不是我過去認(rèn)為的一個(gè)功能模塊)。在文件的表現(xiàn)形式上是一個(gè)addin配置文件,在系統(tǒng)中對(duì)應(yīng) addin 類。
3、extension 擴(kuò)展點(diǎn)
 sharpdevelop中的每一個(gè)插件都會(huì)被掛到 addintree(插件樹) 中,而具體掛接到這個(gè)插件樹的哪個(gè)位置,則是由插件的 extension 對(duì)象中的 path 指定的。在addin 配置文件中,對(duì)應(yīng)于 <extension> 。例如下面這個(gè)功能模塊的配置
<extension path = "/sharpdevelop/workbench/ambiences">
 <class id = ".net" class = "icsharpcode.sharpdevelop.services.netambience"/>
 </extension>
指定了擴(kuò)展點(diǎn)路徑為 /sharpdevelop/workbench/ambiences ,也就是在插件樹中的位置。
4、codon
 這個(gè)是一個(gè)比較不好理解的東西,在 sharpdevelop 的三個(gè)作者寫的書的中譯版中被翻譯為代碼子,真是個(gè)糟糕的翻譯,可以跟handle(句柄)有一拼了。詞典中還有一個(gè)翻譯叫“基碼”,我覺得這個(gè)也不算好,不過還稍微有那么一點(diǎn)意思。
 根據(jù)我對(duì)代碼的理解,codon 描述(包裝)一個(gè)功能模塊,一個(gè)功能模塊對(duì)應(yīng)一個(gè)實(shí)現(xiàn)了具體功能的 command 類。為了方便訪問各個(gè)插件中的功能模塊, codon 給各種功能定義了基本的屬性,分別是 id (功能模塊的標(biāo)識(shí)),name (功能模塊的類型。別誤會(huì),這個(gè)name 是addin文件定義中codon的xml結(jié)點(diǎn)的名稱,id才是真正的名稱),其中name可能是class(類)、menuitem(菜單項(xiàng))、pad(面板)等等。根據(jù)具體的功能模塊,可以繼承codon定義其他的一些屬性,sharpdevelop中就定義了 classcodon、menucodon、padcodon等等。
在addin定義文件中,codon對(duì)應(yīng)于 <extension> 標(biāo)簽下的內(nèi)容。 例如下面這個(gè)定義
<extension path = "/sharpdevelop/workbench/ambiences">
 <class id = ".net" class = "icsharpcode.sharpdevelop.services.netambience"/>
 </extension>
<extension ...> 內(nèi)部定義了一個(gè)codon,<class ...> 表示該codon是一個(gè) class(類),接著定義了該codon的 id和具體實(shí)現(xiàn)該codon的類名icsharpcode.sharpdevelop.services.netambience。運(yùn)行期間將通過反射來(lái)找到對(duì)應(yīng)的類并創(chuàng)建出來(lái),這一點(diǎn)也是我們無(wú)法在以前的語(yǔ)言中實(shí)現(xiàn)的。
再例如這一個(gè)定義
 <extension path = "/sharpdevelop/views/projectbrowser/contextmenu/combinebrowsernode">
 <menuitem id = "compile"
 label = "${res:xml.mainmenu.runmenu.compile}" 
 class = "icsharpcode.sharpdevelop.commands.compile"/>
 <menuitem id = "compileall"
 label = "${res:xml.mainmenu.runmenu.compileall}" 
 class = "icsharpcode.sharpdevelop.commands.compileall"/>
 <menuitem id = "combinebuildgroupseparator" label = "-" />
 ....
</extension>
這個(gè)擴(kuò)展點(diǎn)中定義了三個(gè)菜單項(xiàng),以及各個(gè)菜單項(xiàng)的名字、標(biāo)簽和實(shí)現(xiàn)的類名。這里的codon就對(duì)應(yīng)于系統(tǒng)中的menucodon對(duì)象。
5、command 命令
 正如前文所述,codon描述了一個(gè)功能模塊,而每個(gè)功能模塊都是一個(gè) icommand 的實(shí)現(xiàn)。最基本的 command 是 abstractcommand,根據(jù)codon的不同對(duì)應(yīng)了不同的 command。例如 menucodon 對(duì)應(yīng) menucommand 等等。
6、service 服務(wù)
 插件系統(tǒng)中,有一些功能是整個(gè)系統(tǒng)都要使用的,例如文件訪問、資源、消息等等。這些功能都作為插件系統(tǒng)的一個(gè)基本功能為整個(gè)系統(tǒng)提供服務(wù),我們就叫“服務(wù)”好了。為了便于訪問,這些服務(wù)都統(tǒng)一通過 servicemanager 來(lái)管理。其實(shí)服務(wù)也是一種類型的插件,它們的擴(kuò)展點(diǎn)路徑在目錄樹中的 /services 中。
 理解了這幾個(gè)基本的概念之后,就可以看看 sharpdevelop 的代碼了。從 src/main/startup.cs 看起吧,之后是addin.cs、addintree.cs 等等。
 寫了兩個(gè)小時(shí)了,休息一下。且聽下回分解吧。