如果不能和用別的編程語言編寫的組件進行交互,這種編程技術的含金量就會大打折扣。.Net環境為我們提供了不同編程語言編寫的組件之間相互調用的良好機制。只要按照.Net可操控代碼的標准來編寫組件,對於客戶程序來說,調用者的組件是哪種語言編寫的都無關緊要,調用的方式實際上沒有什麼區別。
下面我們先後使用C++、VB和C#編寫了自己的組件。這是一個簡化的字典組件,字典在構造時沒有裝載語言庫,需要使用LoadLibrary來完成。使用FreeLibrary方法把語言庫卸載。屬性CurrentLibrary表示當前的語言庫。在C#中同時調用了用三種語言編寫的組件,通過比較相信讀者將會一目了然。
18.2.1 C++組件
先看看C++中的組件
程序清單18-3:
//DICTVC.cpp #usingusing namespace System; namespace DICTVE { __gc public class DictionaryComponent //定義字典組件 { private: String* LanguageName; String* AvailableLanguage[]; public: DictionaryComponent() { LanguageName=null; AvailableLanguage=new String*[4]; AvailableLanguage[0]=new String(L"Chinese"); AvailableLanguage[1]=new String(L"English"); AvailableLanguage[2]=new String(L"German"); AvailableLanguage[3]=new String(L"French"); } bool LoadLibrary(String* Language) { for(int i=0;i<4;i++){ if(language==AvailableLanguage[i]) break; } if(i==4){ return false; } LanguageName=language; return true; } __property string* get_CurrentLibrary{ return LanguageName; } } }
首先,我們聲明了一個新的名字空間,用來封裝創建的新的類。
namespace DICTVC{...};
注意到,名字空間不能被嵌套,但可以被分離在多個文件中。一個簡單地源代碼文件也可以包含多個沒有嵌套名字空間。VB和C#中,所有的類都是可操控的。但在C++定義的名字空間中,我們可以包含可操控的和未操控的代碼,所以我們需要特別指定我們新建的類是可操近代的。
__gc public class DictionaryComponent{...};
這個聲明表示類將被在運行時創建,而且受控於垃圾收集器管理的堆中。我們也可能在編譯時指定/CLR選項來保證程序中所有的類都是可操控的。
類的構造函數在每次創建類的實例時都會被調用,構造函數的名稱與類的名稱相同,而且沒有返回類型。
public: DictionaryComponent{...};
而且,因為類應該是可操控的,所以我們必須顯式地通知編譯器數組是一個可操控的對象。因此,在指派字符串時,我們使用了修飾符__gc。
注意:C++沒有對變量進行默認的初始化功能,必須自己手動設置LanguageNamed的值。
LanguageName=null;
Availablelanguage=new String*[4];
下面是LoadLibrary方法,帶有一個字符串類型的參數,返回一個布爾值:
bool LoadLibrary(String* language){ ...... if(i==4) return false; LanguageName=language; return true; } 下面是FreeLibrary方法,沒有參數,也沒有返回值。 void FreeLibrary(){ LanguageName=null; } 最後,我們創建了一個只讀屬性Count: __property string* get_CurrentLibrary{ return LanguageName; }
編譯這個C++組件時的命令選項稍微有些復雜:
cl/CLR/c DICTVC.cpp
link -noentry-dll/out...\Bin\DICTVC.dll DICTVC
這裡,我們需要使用/CLR選項來通知編譯器,生成的代碼裝配必須是可操控的。我們還需要一條獨立的命令來執行鏈接(和C#中直接編譯產生目標代碼不同,C++中必須經過編譯和鏈接兩個過程)。裝配是指在.Net結構框架中能夠被部署、進行版本定義、可重用的物理單元。每一個裝配都建立了一個類型的集合,集合的元素包含基於運行時的類和其它的資源,它們將按照裝配的指定協同工作。裝配的指定說明了哪些組件是裝配的一部分,哪些類型是從裝配中導出的,以及類型的獨立性。運行時環境將使用裝配來定位和綁定你所引用到的類型。
為了方便起見,我們假設組件在當前目錄的“//\Bin”子目錄中被創建。為了指定組件的創建位置,我們使用/out選項來指定輸出文件的路徑全名。
注意,即使我們在指定的輸出文件名中包含了.dll擴展名,我們還必須要附加的-dll選項來告訴編譯器我們將要創建的是一個DLL,而不是一個可執行文件。