即使是在重寫少數幾個方法之後,你很快就明白這不 是一個高產的方法來提供交互功能。簡單的說,使用P/Invoke只能訪問C風格的 Win32方法(在開發上要開銷更多的時間)。
最後一種選擇就是在 Microsoft C++編譯器上使用/CLR開關來混合托管的非托管代碼。如果你編譯你 所有的本地代碼使用/CLR,你就創建了一個基於MSIL的庫,該庫使用本地堆來存 儲所有的數據。這就是說,這樣的C++庫不能直接被C#調用。你必須在你所熟悉 的代碼上創建一個托管的C++庫,用於在托管和非托管類型之間創建一個橋梁, 提供在托管和非托管的堆之間的數據集群支持。這樣的C++庫包含托管類,這些 數據成員是基於托管堆的。這些類同樣包含對本地對象的引用:
// Declare the managed class:
public __gc class ManagedWrapper : public IDisposable
{
private:
NativeType* _pMyClass;
public:
ManagedWrapper( ) :
_pMyClass( new NativeType( ) )
{
}
// Dispose:
virtual void Dispose( )
{
delete _pMyClass;
_pMyClass = NULL;
GC::SuppressFinalize( this );
}
~ManagedWrapper( )
{
delete _pMyClass;
}
// example property:
__property System::String* get_Name( )
{
return _pMyClass- >Name( );
}
__property void set_Name( System::String* value )
{
char* tmp = new char [ value->Length + 1 ];
for (int i = 0 ; i < value->Length; i++ )
tmp[ i ] = ( char )value->Chars[ i ];
tmp[ i ] = 0;
_pMyClass->Name( tmp );
delete [] tmp;
}
// example method:
void DOStuff( )
{
_pMyClass->DOStuff( );
}
// other methods elided...
}
再說一次,這並不是一個像以前使用過的 高產的程序開發工具。這只是代碼重復,而且整個目的都要在托管和非托管數據 之間進行集群數據和thunking。優勢是,你可以從你的本地代碼中暴露出來的方 法和屬性上完成控制。而劣勢是你必須手寫一部份.Net代碼以及一部份C++代碼 。在這兩種代碼之間轉換很容易讓你發生錯誤。你還不能忘記刪除非托管對象。 托管對象不是你 要負責的。這會讓你的開發進度降下來,因為要不斷的檢測這 是否正確。
使用 /CLR 開關聽上去像是一個神話,但對於所有的交互來 說,這並不是一個神彈(magic bullet)。C++裡的模板和異常處理與C#是大不相 同的。寫的很好很高效的C++並不一寫能轉化成最好的MSIL結構。更重要是,編 譯C++代碼時的 /CLR開關並不做確認。正如我前面所說的,這樣的代碼是使用本 地堆:它訪問本地內存。而CLR並不能驗證這些代碼是安全的。調用這些代碼的 程序必須確保有安全許可來訪問不安全代碼。雖然如此,/CLR策略還是最好的一 個方法,在.Net中利用已經存在的C++代碼(不是COM對象)。你的程序不會招致 thunking開銷,而為你的C++庫現在並不在MSIL中,MSIL不是本地的CPU指令。
交互操作是件頭疼的事。在你使用交互之間,認真的考慮寫本地應用程 序。這經常是簡單而且很快的。不幸的是,對於很多的開發人員來說,交互是必 須的。如果你有已經存在的用其它語言寫的COM對象,使用COM交互。如果你有已 經存在的C++代碼,使用 /CLR 開關並托管C++來提供最好的策略來方法已經存在 的本地代碼。選擇最省時間的一個策略,這可能就是“just thro it out”策略。
返回教程目錄