程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Effecitve C#原則46:最小化與其它非托管代碼的交互(2)

Effecitve C#原則46:最小化與其它非托管代碼的交互(2)

編輯:關於C語言

當你在托管代碼和非托管代碼之間,只使用blittable 類型 時,你就最小化了多少必須拷貝的信息呀!你同樣也優化了任何必須發生的拷貝 操作。

如果在數據拷貝時,你不能限制數據類型讓它成為blittable 類 型,你可以使用InAttribute 和OutAttribute 來進行控制。也COM類似,這些特 性控制數據拷貝的方法。In/Out 參數雙向拷貝,In參數以及Out參數是一次拷貝 。確保你應用嚴格限制的In/Out組合,來避免更多不必須拷貝。

最後, 你可以通過申明如何集群數據來提高性能。對於字符串來說這是最常見的。集群 字符串默認是使用BSTRs。這是一個安全的策略,但這也是最低效的。你可以通 過修改默認的集群格式減少額外的拷貝操作,可以使用MarshalAs 特性來修改集 群方式。下面申明了字符串的集群使用LPWStr或者wchar*:

public void SetMsg(
 [ MarshalAs( UnmanagedType.LPWStr ) ] string msg );

這有一個關於處理托管和非托管層上數據的轶事:數據被拷貝 然後在托管和非托管類型之間進行傳輸。你有三個方法業最小化拷貝操作。首先 就是通過限制參數和返回值,讓它們是blittable類型。這應該是首選的。當你 不能這樣做時,應用In和Out特性來最小化必須完成的拷貝和傳輸操作。最後一 個優化就是,很多類型可以不只一種集群方式,你應該選擇最優化的一種。

現在讓我們轉到如何在托管的非托管組件中轉移程序控制。你有三種選 擇:COM交互,平台調用(P/Invoke),以及托管C++。每種方法有它自己的優勢和 劣勢。

COM交互是最簡單的方法來使用已經存在的COM組件。但COM交互也 是在.Net中和本地代碼交互時最低效的一種方式。除非你的COM組件已經有很重 要的利益,否則不要這樣做。不要看也不要想這種方式。如果你沒有COM組件而 要使用這種方法就意味著你要把COM和交互原則學的一樣好。沒時間讓你開始理 解IUnknown(譯注:COM原理中最基本的接口,任何COM都實現了這樣的接口)。那 些這樣做的人都試著從我們的內存中盡快的清理它們。使用COM交互同樣意味著 在運行時你要為COM子系統承擔開銷。你同樣還要考慮,在不同的CLR對象的生命 期管理和COM版本的對象生命期管理之間又意味看什麼。你可以服從CLR的原則, 這就是說做一個你所導入的COM對象有一個析構函數,也就是在COM接口上調用的 Release()。或者你可以自己清楚的使用ReleaseCOMObject()來釋放COM對象。第 一種方法會給應用程序引入運行時的低效(參見原則15)。而第二個在你的程序裡 又是頭疼的事。使用ReleaseCOMObject ()就意味看你要深入到管理細節上,而 這些CLR的COM交互已經幫我們完成了。你已經了解了,而且你認你明白最好的。 CLR請求所有不同,而且它要釋放COM對象,除非你正確的告訴它,你已經完成了 。這是一個極大的鬼計,因為COM專家程序員都是在每個接口上調用Release(), 而你的托管代碼是以對象處理的。簡單的說,你必須知道什麼接口已經在對象上 添加了AddRef,而且只釋放這些(譯注:COM的引用非常嚴格,每個引用都會添加 一個AddRef,釋放時必須明確的給出Release(),而且必須成對使用,而在.Net 對COM進行封裝後,很多時候就是這個引用不匹配而出現資源洩漏)。就讓CLR來 管理COM的生命期,你來承擔性能損失就行了。你是一個煩忙的開發人員,想 在.Net中混合COM資源到托管環境裡,你要學習的太多了(也就是第三個開銷)。

第二個選擇是使用P/Invoke。這是一個更高效的方法來調用Win32的API ,因為你避免了在上層與COM打交道。而壞消息是,你須要為你使用的每個 P/Invoke方法手寫這些接口。越是調用多的方法,越是多的申明必須手寫。這種 P/Invoke申明就是告訴CRL如何訪問本地方法。這裡額外的解釋一下為什麼每個 一個關於P/Invoke的例子裡(也包括下面這個)都使用 MessageBox:

public class PInvokeMsgBox
{
  [ DllImport( "user32.dll" ) ]
  public static extern int MessageBoxA(
   int h, string m, string c, int type );
  public static int Main()
  {
   return MessageBoxA( 0,
    "P/InvokeTest",
    "It is using Interop", 0 );
  }
}

另一個使用 P/Invoke的主要缺點是,這並不是設計成面向對象的語言。如果你須要導入C++ 庫,你必須在你的導入申明中指明封裝名。假設取代Win32的MessageBox API, 你想訪問MFC的C++DLL裡的另外兩個AfxMessageBox 方法。你須要為其中一個方 法創建一個P/Invoke申明:

?AfxMessageBox@@YGHIII@Z

?AfxMessageBox@@YGHPBDII@Z

這兩個申明名是與下面的兩個方法匹配的:

int AfxMessageBox( LPCTSTR lpszText,
 UINT nType, UINT nIDHelp );
int AFXAPI AfxMessageBox( UINT nIDPrompt,
 UINT nType, UINT nIDHelp);

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved